This is a weak reason. In practice, machines that do not represent NULL as zero no longer exist and new designs of this nature would break so much existing code, it would be difficult for them to gain wide adoption in the marketplace. The C standard hasn't decided to require NULL be represented as zero yet (and may never, to preserve compatibility with machines it used to have defined behavior on), but most C code runs on machines where NULL is represented with zero bits.
(You're absolutely correct that the standard does not require NULL be represented with zero bits, though.)
> it's possible for the assertion to fail, since NULL it not guaranteed to be represented in memory by a zero bytes.
Technically correct (which is of course the best kind of correct) but you'd be hard pressed to find a system in 2019 where NULL != (void*)0. The most recent machines with non-zero NULL in the C FAQ entry on the matter (http://c-faq.com/null/machexamp.html) date back to the mid '90s.
This expression is false in any C99 compliant system:
Section 6.3.2.3 [0]:
> An integer constant expression with the value 0, or such an expression cast to type void * , is called a null pointer constant. [1] If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function
> Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.
The technicality of the memset example is that it does not set the bits of the pointer by referring to it as a pointer, so the requirement that 0 behave as if it was a null pointer does not apply.
Nah, NULL is guaranteed to be == (void * )0 by the standard. The allowed divergence is in how (void * )0 is represented as bits in memory, i.e., memcmp(zeroes, (ptr = NULL), sizeof(ptr)) == 0?
But talking about the actual bit representation. A zero value as a special pointer with the magic property of being invalid is a convention for C on x86, right?
I assume it has to do with it's fast to check the zero-flag in EFLAGS register when doing checks for null pointers.
That will never happen on current or future platforms, and is not a big concern. Or perhaps it'd be better to say that if it ever does happen on a future platform, then a few memset calls are going to be the least of your problems when porting legacy C code to that platform.
However, what has bitten me is memsetting structures that I later turn into full-fledged classes in C++. Oops, there went the VMT.
Designated initializers are very nice, as is the ability (in C++) to provide initial-value assignments that run before the constructor.
It does not matter if there are any architectures like that. Relying on that fact is still an undefined behavior. The compiler is allowed to produce any code it wants.
If you use memset to initialize structure with pointers with 0 and then test if the pointer are NULL, the compiler could assume that the pointer was not properly initialized and remove the if completely, or actually even remove the whole function.
In the real world it rarely matter what a theoretical compiler is allowed to do, but what specific compilers actually do. UB only matters when compilers actually "exploit" it.
Yeah, I saw the comment and big block of bulls in bad tar. Here's two from memory: parent pointer in tree_entry, although it seems unused anyway. buff pointer in the link hash thing. (My bad, I looked at it on my laptop, which is not here anymore. I can drop an email later.)
struct S {size_t a, void *p;};
foo = (struct S) {0};
Does the standard require the compiler to set any pointers to NULL, or will everything be implicitly zeroed leaving pointers possibly improperly initialized to NULL?