News for hackers. Stuff that matters.
Re:C++ Annotations by cjensen on Saturday November 24, 2018 @01:54AM (#18520857)
So I immediately checked my favorite language gotcha, the macro NULL. The text is entirely wrong. The macro NULL is harmful in both C and C++. It is not "stylistic" AT ALL.

Here's the problem with the macro: the macro NULL can be either 0 or can be (void * ) 0. The issue is that the former can be accidentally interpreted as an integer depending on context.

In both C and C++, this manifests when you pass NULL to a varargs function. Instead of passing in a null pointer, the compiler may instead pass in an integer zero. If pointers and ints have different sizes, hilarity ensues. If the null pointer does not have the same bit representation as int zero, hilarity ensues.

In C++, this happens even more commonly. If there is an operator overload and you pass in NULL, then if NULL is 0 it will chose the int overload, if NULL is (void * ) 0 it will chose a pointer overload.

Never use NULL. Ever.

Re:C++ Annotations by minipci1321 on Saturday November 24, 2018 @02:48AM (#18520980)
> ... when you pass NULL to a varargs function. Instead of passing in a null pointer, the compiler may instead pass in an integer zero.

How can that happen? If I recall the standard, variadic functions have default promotion of non-declared args: integral promotion for integral types, floats to doubles. Why would the compiler want to convert a pointer (which (void*)0 is) to an integer?

Re:C++ Annotations by taejo on Saturday November 24, 2018 @04:49AM (#18521289)
> a pointer (which (void* )0 is)

In C: the macro NULL is an implementation-defined null pointer constant, which may be

> an integer constant expression with the value ​0​

> an integer constant expression with the value 0 cast to the type void*

In C++: the macro NULL is an implementation-defined null pointer constant, which may be

> an integral constant expression rvalue of integer type that evaluates to zero (until C++11)

> an integer literal with value zero, or a prvalue of type std::nullptr_t (since C++11)

Re:C++ Annotations by cjs_2 on Saturday November 24, 2018 @02:09AM (#18520882)
What would you suggest using instead? The actual (void *) 0?
Re:C++ Annotations by CopperWing on Saturday November 24, 2018 @02:17AM (#18520902)
In C++, nullptr.
Re:C++ Annotations by cjs_2 on Saturday November 24, 2018 @02:40AM (#18520959)
And in C?
Re:C++ Annotations by craigching on Saturday November 24, 2018 @03:02AM (#18521017)
In C, always use 0 and check for 0, it's the only safe way. For C++, it depends on the standard you're using.
Re:C++ Annotations by fanf2 on Saturday November 24, 2018 @02:59PM (#18523718)
Except when calling a varargs function, when you need to cast to the correct pointer type
Re:C++ Annotations by guipsp on Saturday November 24, 2018 @04:34AM (#18521249)
But 0 isn't always null right?
Re:C++ Annotations by cjensen on Sunday November 25, 2018 @09:11PM (#18530509)
Literal zero in a pointer context is interpreted by the compiler to mean "the null pointer." The compiler then compiles the null pointer into the code.
Re:C++ Annotations by guipsp on Monday November 26, 2018 @03:26AM (#18531894)
But then how do you get a pointer to zero (not null) in those systems?
Re:C++ Annotations by cjensen on Monday November 26, 2018 @12:36PM (#18535117)
First, that's inherently non-portable. That aside...

On most systems, the null pointer happens to be a pointer to address zero. For other systems, e.g. 8086 16-bit mode, you can create a intptr_t (which is the same size as a pointer) and set it to zero. Then cast it to a pointer. Such casting is always done bitwise, so it will work.

The compiler knows to turn the following into the null pointer

  void *p = (void *) 0;
but the compiler will NOT turn the following into a null pointer

  void *p = (void *) (uintptr_t) 0;
because the literal 0 is now in an integer context, not a pointer context.
Re:C++ Annotations by Koshkin on Monday November 26, 2018 @05:19PM (#18537358)
BTW 0 is a valid literal value of a pointer type (so you do not need a cast).
Re:C++ Annotations by guipsp on Wednesday November 28, 2018 @03:33AM (#18550067)
Thank you!
Re:C++ Annotations by cjensen on Sunday November 25, 2018 @09:09PM (#18530500)
Prior to nullptr, generally I used literal 0. In those cases which require disambiguation, I used (void * ) 0.
Re:C++ Annotations by Fronzie on Saturday November 24, 2018 @03:41AM (#18521118)
In C++ it'd be nullptr.
Re:C++ Annotations by stinos on Saturday November 24, 2018 @03:52AM (#18521149)
the macro NULL can be either 0

When is that the case? Like, in some specific library/compiler implementations?

Re:C++ Annotations by taejo on Saturday November 24, 2018 @04:55AM (#18521303)
In C and C++, 0 is an allowed definition of NULL. Before C++11, 0 was the only allowed definition of NULL.