3 ms·
Aren't there platforms where pointers have additional type or space information encoded that is orthogonal to the numeric address? It's only by convention that
by throwway120385 3y ago
Aren't there platforms where pointers have additional type or space information encoded that is orthogonal to the numeric address? It's only by convention that NULL == 0 because on platforms like Intel & ARM you would typically not use the first page. But that's only a convention, and you could just as easily put a null page at the top of your address space, especially in systems with an MMU where mappings can be added, removed, or remapped as-needed.
- LegionMammal978 3y agoIn C, the integer 0 is explicitly defined to convert to a null pointer for all assignments, casts, comparisons, etc., regardless of what the pointer's "actual" value is. The only time where you can see that a null pointer doesn't have numeric value 0 is when you manipulate its object representation with memset, memcpy, etc. The compiler is also at liberty to return whatever it wants when you convert a null pointer to an integer, except that converting it back must produce a null pointer (if it's at least as wide as intptr_t).
- mananaysiempre 3y ago> It's only by convention that NULL == 0 [...] and you could just as easily put a null page at the top of your address space [...]. Technically NULL == 0 always because the standard special-cases zero-valued integer constant expressions; (uintptr_t)NULL == 0 or NULL == *(void **)calloc(1, sizeof(void *)) is another matter :) Language lawyering aside, a non-all-zeroes representation of NULL will probably blow up most C programs [e.g. static-storage-duration initialization is now not the same as calloc or memset(,0,) and is even type-specific]. Like CHAR_BIT, that’s a joint that technically exists but has been rusted for decades (pun not intended).
- kazinator 3y agoThere is no problem with static initializations with a null pointer that is not all zero bits, or a floating-point 0.0 that is not all zero bits. Those values just cannot participate in the "BSS" trick, whereby everything that is zero-initialized is put into a special section that doesn't actually exist in the program image, and is only provided on startup. Those values would go into the initialized data section. The problem with 0.0 or null pointers not being all zero bits is all the code that uses calloc or memset zero. If this is on some specialized platform (e.g. DSP chip), it might not matter that vast quantities of C code are not portable. In general, compiler (and to a great extent instruction set architecture!) designers are quite hamstrung by the expectations of C programmers and programs; that has been the situation for some thirty years now. Today, you could not sucessfully introduce a system in which pointers to bytes (void , char ) have a different representation from other pointers (let alone different size, lord forbid).
- pjmlp 3y agoIf we if ignore ongoing efforts on hardware memory tagging since SPARC ADI.
- kazinator 3y agoHardware memory tagging schemes carefully avoid breaking common C idioms. What breaks are - truly dubious programs which use pointers in ways they really shouldn't, and are almost certainly just bugs; like use-after-free. When a pointer with an out-of-date tag is passed to the library, that is pretty much a confirmed use-after-free, which is not a legitimate idiom of non-maximally-portable C, like assuming that all pointers are the same size. - C programs which manipulate the pointer representation: e.g. run-times for dynamic languages that put their own tags in pointers. These can easily work around tagging. (I've dealt with this on Android recently, quite easily. For the affected objects, I strip the tag away, and work with the untagged pointers. When it's time to pass the pointer back to Android's library, I put the tag back. All other code works as before.
- pjmlp 3y agoYeah, but all of that falls off ISO C defined semantics.
- mananaysiempre 3y agoIncidentally, AFAICT C23 now allows stashing log2 alignof(max_align_t) bits in pointers in a portable (if awkward) manner: for example, for a char pointer p, the lowest such bit can be retrieved with memalignment(p)<2 and masked off with p-(memalignment(p)<2). (C++’s std::aligned would be less awkward, but, well, memalignment() is what we get.) You still can’t portably store pointers and integers (or doubles) in the same place and distinguish them, though.