Programming thread

  • Want to keep track of this thread?
    Accounts can bookmark posts, watch threads for updates, and jump back to where you stopped reading.
    Create account
For all the "C but a bit higher level" pretenders there aren't many "C but a bit lower level" languages that learn from today's programming understanding. I think there's a real niche here. Maybe this is the era of the compiled Scheme?
like many things in the lisp world, this was invented in the 20th century by some nigger who was working on something else, and it wasn't properly documented so nobody used it and it eventually became obsolete
in this case it was parts of the runtime system of scheme48 that were made using a scheme subset (read: dialect that you can polyfill to run in regular scheme with a few macros) that would straightforwardly compile to c and work with no runtime
it's called "prescheme" and it's in a very dire state like stalin and has some extremely bad limitations
although last time i heard somebody's trying to port it to modern r7rs implementations (read: guile) and make it usable as a general-purpose c-like language

imagine c with a lispy syntax and full hygienic scheme macros. i can hear a bunch of rustniggers hanging themselves right now 😌
 
i did find the c syntax for pointers hard for a while (thanks k&r for using the asterisk for like 3 different things)
Yeah, makes sense that people confuse the implementation (c pointer syntax) with the concept (pointers themselves) and think the implementation defines the concept. I have fallen into that trap plenty of times myself.
 
What language would the sneedlang compiler be written in? (before the self-hosted compiler)
just write the compiler in r7rs scheme and a small runtime system in holyc then it can be bootstrapped onto god's temple when ready
c-based runtimes can be written for heathen systems unless we somehow complete the systems language before the novelty of templeos wears off

note: make sure to keep a clean bootstrap path at all times so that anybody can quickly set up their own sneed compiler from just the source
 
was researching on ways to make global constants in c
during my research i've found this on cppreference
1757679232266.webp

and i really have one question — why?
 
was researching on ways to make global constants in c
during my research i've found this on cppreference
View attachment 7904940
and i really have one question — why?
Good question. Aside from the reason being C++ is AIDS, we have Appendix C (C++11, C.1.2):
Change: A name of file scope that is explicitly declared const, and not explicitly declared extern, has internal linkage, while in C it would have external linkage

Rationale: Because const objects can be used as compile-time values in C++, this feature urges programmers to provide explicit initializer values for each const. This feature allows the user to put const objects in header files that are included in many compilation units.
I have attached and linked to the standard because it is not very easy to hunt down the master copy.
 

Attachments

Last edited:
Good question. Aside from the reason being C++ is AIDS, we have Appendix C (C++11, C.1.2):
thats a really shit rationale considering static const Foo foo = foo(); does the same thing as far as im aware
 
yeah and i repeated it, what are you gonna do about it :smug:

that reminds me of how i thought i didnt understand pointers, because r/programmerhumor was treating it like something advanced and hard to understand. far cry from "just a memory address lol"
When I learned about pointers in middle school I conceptually graphed them on paper using two rows of cells kind of like those daily pillboxes old people have: the top row was memory addresses (made-up, typically starting from 42) and the bottom row was the values at those addresses. That should be good enough for ** and my understanding is that if you reach *** there's been a problem.
For all the "C but a bit higher level" pretenders there aren't many "C but a bit lower level" languages that learn from today's programming understanding. I think there's a real niche here. Maybe this is the era of the compiled Scheme?
Forth?
 
That should be good enough for ** and my understanding is that if you reach *** there's been a problem.
Until you try to reverse engineer something and end up with pointer signatures such as
Code:
(**(code **)(local_8 + 0x10))(local_110,0x80000000,1,0,3,0x10000000,0)
because of vtables. That's when you start to cry yourself to sleep. (I think that's a pointer to a pointer for a function that returns a function pointer that then gets called)

local_8 is probs the this pointer, with 0x10 being the offset to the actual first function
this then is a pointer to a pointer to a function, so I already made a mistake. The (code **) is a cast, rather than function call. So, double deref.
that function than takes in local_110, what looks to be a flag, some random variables, another flag and a 0

No idea where the local 110 comes from though
 
Last edited:
I think local_110 is this and local_8 is a cached pointer to the vtable to avoid a double indirection on every virtual call.

edit: I should probably make a go at deciphering it:
C++:
code **vtable_entry = (code **) (local_8 + 0x10);  // 16th entry in vtable
code *method = *vtable_entry;  // fetch function pointer from vtable
auto result = (*method)(local_110 /* this */, ...);  // indirect function call

What I can't figure out is why it uses *(code **)(local_8 + 0x10) rather than ((code **) local_8)[0x10], equivalent to *((code **) local_8) + 0x10). I assume it's because casting before indexing would change the scaling factor applied to the index of 0x10 to calculate the actual byte offset, but I don't see how it would even work if sizeof(code *) != sizeof(*local_8). Even if you had 64-bit pointers but know that all code will be within the first 4GB of address space and used 32-bit addresses in the vtable, you'd still need to perform the first dereference to get the 32-bit pointer before casting to 64 bits. Could each entry in the vtable contain two data items, so you need a larger datatype for calculating the offset, and the function pointer is the first item in each entry and therefore has the same address as the whole entry? .It seems very odd, and I've been awake for 16+ hours, so I'll sleep on it and take another crack at it tomorrow.
 
Last edited:
That should be good enough for ** and my understanding is that if you reach *** there's been a problem.
Three layers of indirection is excusable, and there are good reasons to even go higher, though increasing indirection causes increasing mental strain, so you should abstract as much of that away as possible if you need more.

Let's walk through this.

char* n is, for example, your typical string. The pointer goes to the first letter.

char** argv is, for example, your list of arguments. This means that, in memory, you have several consecutive pointers, each pointing at a null-terminated string. In practice, this ends up being a single hunk of memory, but you don't know that, and you probably shouldn't assume it, though assuming it can bring fun hacks.

char** is a lookup table.

Now, consider you're doing some argument parsing. You have a flag like "--nigger" that the argument syntax lets you put anywhere. So you handle it. But now you want to have an array of just the files, no flags. This is the job for a lookup table: char**. When you say "should be good enough for **" that's what most people mean: if you just want the strings, you can simply make a copy of the argv pointers and omit the pointers that point to things you don't want.

But wait, what if our opt parsing also can modify strings? What if it modifies the pointers in argv? What you need here is a pointer to a char**, a pointer to (a pointer to a pointer), so you're sure that you're actually pointing at the appropriate argv pointer. This calls for char***. You probably want to hide this in an auxiliary function or something to make it cleaner. But here's a basic sketch of a justification for arbitrary pointer nest depth. The deeper the depth, the less you'd expect to find justification, as this is contingent on specifically needing a pointer to the last level of nesting, and this requires a circumstance where duplicating a pointer at a lower nest depth isn't adequate.

It should be clear from this little illustration how much harder the justification for deeper nesting becomes as you deepen. But remember, code serves. If "bad code" serves, it isn't all that bad code.
 
It's decompiled by ghidra for a game that is over 20 years old.
The deeper the depth, the less you'd expect to find justification, as this is contingent on specifically needing a pointer to the last level of nesting, and this requires a circumstance where duplicating a pointer at a lower nest depth isn't adequate.
Also, a lot of pointers to pointers are hidden behind structs. You can have a pointer to a struct that also contains a pointer to another struct which contains yet another pointer to one. and so on. Which also easily results in arbitrary pointer nesting depth.
 
What I can't figure out is why it uses *(code **)(local_8 + 0x10) rather than ((code **) local_8)[0x10], equivalent to *((code **) local_8) + 0x10). I assume it's because casting before indexing would change the scaling factor applied to the index of 0x10 to calculate the actual byte offset, but I don't see how it would even work if sizeof(code *) != sizeof(*local_8). Even if you had 64-bit pointers but know that all code will be within the first 4GB of address space and used 32-bit addresses in the vtable, you'd still need to perform the first dereference to get the 32-bit pointer before casting to 64 bits. Could each entry in the vtable contain two data items, so you need a larger datatype for calculating the offset, and the function pointer is the first item in each entry and therefore has the same address as the whole entry? .It seems very odd, and I've been awake for 16+ hours, so I'll sleep on it and take another crack at it tomorrow.
this is reverse engineering and it is common for the decompiler to spit out some incredibly weird code from time to time
 
Back
Top Bottom