7 ms·
Another reason to not memset structures: In the code struct foo { void * bar; } baz; ... memset(&baz, 0, sizeof(struct foo));
by cperciva 8y ago
Another reason to not memset structures: In the code
struct foo {
void * bar;
} baz;
...
memset(&baz, 0, sizeof(struct foo));
assert(baz.bar == NULL);
it's possible for the assertion to fail, since NULL it not guaranteed to be represented in memory by a zero bytes.
- lpolzer 8y agoYou are right in theory, but I have yet to come upon a compiler that will use something other than zero for null.
- flohofwoe 8y ago...are there any remaining architectures where NULL is not zero? The examples listed here are all historical: http://c-faq.com/null/machexamp.html http://c-faq.com/null/machexamp.html
- ogoffart 8y agoIt 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.
- flohofwoe 8y agoIn 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.
- CamperBob2 8y agoThat 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.
- ThrowawayR2 8y ago> 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 http://c-faq.com/null/machexamp.html) date back to the mid '90s.
- cperciva 8y ago> you'd be hard pressed to find a system in 2019 where NULL != (void *)0 You'd be hard pressed to find a system at any time where NULL is not equal to a compile-time constant zero. ;-)
- hedora 8y ago> The Prime 50 series used segment 07777, offset 0 for the null pointer, BAM!!! (All I had to do was click on the link in the comment you replied to, but the pedantry in this subthread is glorious, and I had to contribute — downvoters, this is your chance to school me on HN etiquette!)
- cperciva 8y agoYou're missing the point. "(void *)0" is guaranteed to be a NULL pointer, even when said pointer is not represented in memory by zeroes.
- gizmo686 8y ago>NULL != (void* )0. 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. [0] http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf [1] In text footnote: The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.17 EDIT: Formatting
- paavoova 8y agoSo if you're zeroing out a struct like so 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?
- loeg 8y agoThe pointers are required to be initialized to NULL in your example (even if the representation is different from memset of zero).
- deleted 8y ago[deleted]
- deleted 8y ago[deleted]
- loeg 8y agoThis 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.)
- saagarjha 8y agoI feel like a compiler is within its rights to optimize out that check if it so wishes, though.
- tedunangst 8y agoAre you accepting bug reports for such issues in tarsnap? :)
- cperciva 8y agoYes. If you look at the commit history you'll find that we've fixed a few of them already.
- tedunangst 8y agoYeah, 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.)
- cperciva 8y agoThanks! I'll try to remember about this when I'm back at my laptop but an email will make sure I don't forget. FWIW I'm less strict about standards compliance in the libarchive-derived code, since that frobs lots of unportable bits anyway.
- shaklee3 8y agoUsed to read your blog several years ago, and really enjoyed it. Good seeing your name pop up again.