Sujet : Re: technology discussion → does the world need a "new" C ?
De : cr88192 (at) *nospam* gmail.com (BGB)
Groupes : comp.lang.cDate : 06. Jul 2024, 20:33:16
Autres entêtes
Organisation : A noiseless patient Spider
Message-ID : <v6c688$3uf4o$1@dont-email.me>
References : 1 2 3 4 5 6 7 8 9
User-Agent : Mozilla Thunderbird
On 7/6/2024 1:26 PM, James Kuyper wrote:
On 7/6/24 04:51, BGB wrote:
...
Yeah, and in the 1D case, an array can be seen as functionally an
implicitly defined pointer with an assigned size and preassigned
backing memory.
>
Granted, C generally allows one to see the backing memory, but not the
implicit pointer to said backing memory. I guess one could argue that
if one can't take the address of it, it doesn't exist, but yeah...
C won't let you take that pointer's address because it need not exist,
and in my experience, usually doesn't. Compilers that I'm familiar with
often store all objects that are local to given scope in a single block
of memory whose starting address is stored in a register. No memory is
set aside to store separate pointer objects pointing to any of those
individual objects. When a pointer value pointing at one of those
objects is needed, a fixed offset is added to the address stored in that
register. Are you familiar with any compilers that handle such things
differently? I make no claim to wide knowledge of compilers, but the
compilers that I used which work that way are among the most widely used
C compilers.
In my compiler (BGBCC), such an internal pointer exists for arrays and structures in the local stack frame.
No separate pointer exists inside of things like structs, where, as can be noted, the array exists at a fixed size and location.
So, eg:
void Foo()
{
int a[100];
...
}
There is both the space for 100 integers reserved in the stack frame, and a variable 'a' which exists as an implicit pointer to that location.
But, say:
void Foo()
{
int a[8192];
...
}
There is no space reserved on the stack, and the array is instead allocated dynamically (from the heap). In this case, the "a" variable exists as a pointer to that location in memory.
Similar treatment also applies to structs.
...
Doesn't currently apply to global structs or arrays though, but with some recent experiences, it might almost make sense (dealing with programs with unwieldy large ".bss" sections, and in NOMMU contexts it may be easier to perform a number of smaller allocations than to locate a single large contiguous chunk of memory).
Granted, this would be more of an issue:
The likely way to do this would be to have the program allocate and zero the memory the first time it is accessed, but having the compiler add code to check and conditionally allocate global objects, seems undesirable.
Similarly, allocating it all up-front on program startup would have its own issues (and as-is would not work for dynamically loaded DLLs).
For my Quake3 porting effort, had ended up doing some of this manually (since, as noted, at first Quake3's ".bss" section was big enough to break stuff; by exceeding an 8MB hard limit that currently exists in my compiler, mostly due to part of how it is internally representing relocations).
If not for this limit, the PE32+ format is theoretically limited to around 2GB or so, but as-is, a 2GB PE image would not be loadable anyways.
My "PEL4" format is not strictly PE32+, but in this case the differences don't really matter (PEL4 mostly differing from PE32+ in that it drops the MZ header and adds LZ4 compression; among a bunch of other mostly minor differences). I did make creative use of the "Global Pointer" entry in the "Data Directory", but it isn't too far removed from how it worked in WinCE, so alas... (But, specific information on WinCE is hard to find, most information focusing on desktop versions of the OS, but can note that they also dropped the MZ stub, as it is basically irrelevant if MS-DOS is no longer involved; but I went slightly further and also dropped the MZ header, saving roughly 64 bytes in this case).
So, say, first 4 bytes of file:
"MZ\0\0": Traditional PE-COFF
"PE\0\0": No MZ Header, uncompressed.
"PEL4": No MZ Header, LZ4 compressed (after the PE headers).
Loading a PE image generally involves reading the thing into RAM, whereas a PEL4 image generally involves reading the headers, and then decompressing the rest of the image into the destination address.
The MZ+PE format is basically similar. Though, besides the difference in removing the MZ header, also a different checksum algorithm is used (the original MZ checksum was weak; so used a "slightly stronger" checksum which was better able to detect things like if the LZ4 decompression or similar went amiss).
...