Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I see that after 50 years, C has finally gained an official null pointer value and type! "nullptr" and "nullptr_t".

That wouldn't be so interesting, but it highlights the complexity of specifying a language and implementing a specification. For what sounds at first hearing a lot like "#define nullptr 0" the Clang release notes identify 7 syntactic cases where the C standard and the C++ standard disagree about whether "nullptr" should be acceptable in a location. Clang takes each side about equally and it sounds like they are waiting for the standards groups to fix the standards.



It's a very common pattern to memset to zero structs with pointers to initialize them. What happend now with this new "feature"?


Nothing changes. memseting a struct to zero has always been and still is implementation defined behavior, as there are no guarantees on the bit representation of a null pointer. [1]

The C11 standard says that a null pointer constant is defined as follows: "An integer constant expression with the value 0, or such an expression cast to type void , is called a null pointer constant."

The new definition is: "An integer constant expression with the value 0, such an expression cast to type void , or the constant nullptr are all a null pointer constant."

The reason for adding nullptr, is because NULL is roughly defined as a macro that expands to "0" or "(void*)0". This causes trouble with the addition of type detection trough _Generic and now typeof.

[1] https://c-faq.com/null/machnon0.html


memseting a struct to zero has always been and still is implementation defined behavior, as there are no guarantees on the bit representation of a null pointer.

The number of bits in a char has also been implementation defined, yet most if not all code either doesn't care, or assumes it to be 8. This is another one of those "in theory, theory and practice are the same; in practice, they're not" things.


N.B. nonzero bitpattern nullptrs are common in C++ for pointer-to-member s, which are typically implemented as an offset from the start of the structure - with an all-0 bitpattern being a valid non-null pointer to the first member of said structure.

    struct S { int i; };
    int S::*a = &S::i;   // probably  0 under the hood
    int S::*b = nullptr; // probably -1 under the hood
    int S::*c = 0;       // probably -1 under the hood (no typo!)
Consider using brace initializers as an ergonomic alternative:

    struct S d = { 0 };
    struct S e = {}; /* as of C23 or C++ */


That's exactly the point of "implementation defined". The code is fine on all those compilers/architectures where the expectation is valid. It just isn't portable to those exotic/hypothetical architectures where it doesn't, which apparently doesn't bother you in your practice. Nothing wrong with that.


The null address isn't necessarily 0. When a literal 0 is assigned to a pointer it can be magically changed to a platform's true null. Memset() doesn't have this behavior. This isn't relevant on any modern systems but it is an affordance of the C standard. That is the true significance of nullptr. It obsoletes the magic 0 literals.


Sure but on what modern platform isn't null equal to 0? Do modern C standards need to support hardware that no longer exists and will likely never exist?


Just like with undefined behaviour, IMHO the C standards are deliberately underspecified to allow the language to remain applicable to just about any feasible computer.


Consider using = { 0 } instead.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: