Subtraction of two nullptr values guaranteed to be zero?
Yes, that is valid. It would be undefined in C, but C++ has added a special exception to the -
operator to define the behaviour.
5.7 Additive operators [expr.add]
7 If the value
0
is added to or subtracted from a pointer value, the result compares equal to the original pointer value. If two pointers point to the same object or both point one past the end of the same array or both are null, and the two pointers are subtracted, the result compares equal to the value0
converted to the typestd::ptrdiff_t
.
Can we subtract NULL pointers?
Subtracting two NULL pointers is not allowed. Section 6.5.6p9 of the C standard states:
When two pointers are subtracted, both shall point to elements of the
same array object, or one past the last element of the array
object; the result is the difference of the subscripts of the
two array elements. The size of the result is
implementation-defined, and its type (a signed integer type) is
ptrdiff_t defined in the header. If the result is not
representable in an object of that type, the behavior is
undefined. In other words, if the expressions P and Q point to,
respectively, the i
-th and j
-th elements of an array object, the expression (P)-(Q) has the value i−j provided the value fits in an object of type ptrdiff_t . Moreover,
if the expression P points either to an element of an array object or
one past the last element of an array object, and the expression Q
points to the last element of the same array object, the expression
((Q)+1)-(P) has the same value as ((Q)-(P))+1 and as
-((P)-((Q)+1)) , and has the value zero if the expression P points one past the last element of the array object, even
though the expression (Q)+1 does not point to an element of the array
object.
Because neither pointer points to an array object, the behavior is undefined.
You also can't subtract two void *
because void
is an incomplete type, and pointer subtraction depends on knowing the size of the pointed-to object. You could cast each pointer to a intptr_t
and subtract those, however that would give you the byte difference between the pointers, not the index difference.
Is the behavior of subtracting two NULL pointers defined?
In C99, it's technically undefined behavior. C99 §6.5.6 says:
7) For the purposes of these operators, a pointer to an object that is not an element of an
array behaves the same as a pointer to the first element of an array of length one with the
type of the object as its element type.[...]
9) When two pointers are subtracted, both shall point to elements of the same array object,
or one past the last element of the array object; the result is the difference of the
subscripts of the two array elements. [...]
And §6.3.2.3/3 says:
An integer constant expression with the value 0, or such an expression cast to type
void *
, is called a null pointer constant.55) 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.
So since a null pointer is unequal to any object, it violates the preconditions of 6.5.6/9, so it's undefined behavior. But in practicality, I'd be willing to bet that pretty much every compiler will return a result of 0 without any ill side effects.
In C89, it's also undefined behavior, though the wording of the standard is slightly different.
C++03, on the other hand, does have defined behavior in this instance. The standard makes a special exception for subtracting two null pointers. C++03 §5.7/7 says:
If the value 0 is added to or subtracted from a pointer value, the result compares equal to the original pointer value. If two pointers point to the same object or both point one past the end of the same array or both are null, and the two pointers are subtracted, the result compares equal to the value 0 converted to the type
ptrdiff_t
.
C++11 (as well as the latest draft of C++14, n3690) have identical wording to C++03, with just the minor change of std::ptrdiff_t
in place of ptrdiff_t
.
Subtracting null pointer from a normal pointer?
It has undefined behaviour, since pointer arithmetic is only defined within an array.
In practice, on a machine that represents pointers by a numerical address, and with sufficiently large integers, and a null pointer represented by address zero, it will convert a byte address into a word address. That is, it gives the number of int
-sized lumps of memory between the null pointer's address and the address p
.
Also there was a comment that this is a pure and re-entrant function.
"Pure" means that it has no side-effects, and the result only depends on its inputs. "re-entrant" means that it's safe to call while it's already in progress (for example, from an interrupt handler) - it has no internal static data.
Is NULL guaranteed to be 0?
Is NULL guaranteed to be 0?
According to the standard, NULL
is a null pointer constant (i.e. literal). Exactly which one, is implementation defined.
Prior to C++11, null pointer constants were integral constants whose integral value is equal to 0, so 0
or 0l
etc.
Since C++11, there is a new null pointer literal nullptr
and NULL
may be defined as being nullptr
. (And thus literal interpretation of Bjarne's quote has become obsolete).
Prior to standardisation: NULL
may be defined as (void*)0
in C. Since C++ was based on C, it is likely that some C++ dialects pre-dating the standard might have used that definition, but such definition is not conformant with standard C++.
And for completeness: As explained in more detail in SO post linked in a comment below, null pointer constant being 0 does not necessarily mean that the value of the null pointer address is 0 (although the address being 0 is quite typical).
What can be concluded about this:
- Don't use
NULL
to represent the number zero (use0
with appropriate type suffix if appropriate), nor to represent a null-terminator character (use'\0'
). - Don't assume that
NULL
resolves to a pointer overload. - To represent a null pointer, don't use
NULL
but instead usenullptr
if your standard is >= C++11. In older standard you can use(T*)NULL
or(T*)0
if you need it for overload resolution... that said there are probably very few cases where overloading integers with pointers makes any sense. - Consider that the definition may differ when converting from C to C++ and vice versa.
- Don't memset (or type pun) zero bits into a pointer. That's not guaranteed to be the null pointer.
Does both NULL and nullptr point to same address or NULL points to nowhere? (I have seen in many places that nullptr points to zero address)
It might be useful to clear up some terminology. A pointer points to an object. The value of a pointer is an address value. There is a special address value for pointers that do not point to an object. We call such pointers "null pointers". When you assign the NULL
or nullptr
values to a pointer, it becomes a null pointer.
Since all null pointers compare equal, static_cast<void*>(NULL) == static_cast<void>(nullptr)
.
Can I guarantee that the address of nullptr is always 0?
Yes.
A pointer initialised from nullptr
is a null pointer.
Comparing a null pointer to the literal 0
(or to a std::nullptr_t
, which nullptr
is; together these are null pointer constants) yields true
, always.
- http://eel.is/c++draft/basic.fundamental#14
- http://eel.is/c++draft/conv.ptr#1
You can't do this with any old expression, though; even if integer i
is 1, i-i
is not a valid null pointer constant, despite evaluating to 0 at runtime. Your
program will not compile if you try to do this. Only the literal 0
is a valid null pointer constant that can be compared to pointers.
Also, that does not necessarily mean that it has all bits zero, though! Much like how converting a bool
to int
gives you zero or one, but the actual underlying bits of the bool
can be whatever the implementation likes.
Finally, note that your terminology is slightly off; per [support.types.nullptr/1]
, nullptr
itself has no address that can be taken
Can I use NULL as substitution for the value of 0?
Am I allowed to use the NULL pointer as replacement for the value of 0?
No, it is not safe to do so. NULL
is a null-pointer constant, which could have type int
, but which more typically has type void *
(in C), or otherwise is not directly assignable to an int
(in C++ >= 11). Both languages allow pointers to be converted to integers, but they do not provide for such conversions to be performed implicitly (though some compilers provide that as an extension). Moreover, although it is common for converting a null pointer to an integer to yield the value 0, the standard does not guarantee that. If you want a constant with type int
and value 0 then spell it 0
.
- Am I might crossing into Undefined Behavior with this?
Yes, on any implementation where NULL
expands to a value with type void *
or any other not directly assignable to int
. The standard does not define the behavior of your assignment on such an implementation, ergo its behavior is undefined.
- is it permissible to operate with the NULL in that way?
It is poor style, and it will break on some systems and under some circumstances. Inasmuch as you appear to be using GCC, it would break in your own example if you compiled with the -Werror
option.
- Is there anything wrong about to use NULL as numerical value in arithmetical expressions?
Yes. It is not guaranteed to have a numerical value at all. If you mean 0 then write 0, which is not only well defined, but shorter and clearer.
- And how is the result in C++ to that case?
The C++ language is stricter about conversions than is C and has different rules for NULL
, but there, too, implementations may provide extensions. Again, if you mean 0 then that's what you should write.
How to write C/C++ code correctly when null pointer is not all bits zero
According to the C spec:
An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant. 55) 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.
So 0
is a null pointer constant. And if we convert it to a pointer type we will get a null pointer that might be non-all-bits-zero for some architectures. Next let's see what the spec says about comparing pointers and a null pointer constant:
If one operand is a
pointer and the other is a null pointer constant, the null pointer
constant is converted to the type of the pointer.
Let's consider (p == 0)
: first 0
is converted to a null pointer, and then p
is compared with a null pointer constant whose actual bit values are architecture-dependent.
Next, see what the spec says about the negation operator:
The result of the logical negation operator ! is 0 if the value of its
operand compares unequal to 0, 1 if the value of its operand compares
equal to 0. The result has type int. The expression !E is equivalent
to (0==E).
This means that (!p)
is equivalent to (p == 0)
which is, according to the spec, testing p
against the machine-defined null pointer constant.
Thus, you may safely write if (!p)
even on architectures where the null pointer constant is not all-bits-zero.
As for C++, a null pointer constant is defined as:
A null pointer constant is an integral constant expression (5.19)
prvalue of integer type that evaluates to zero or a prvalue of type
std::nullptr_t. A null pointer constant can be converted to a pointer
type; the result is the null pointer value of that type and is
distinguishable from every other value of object pointer or function
pointer type.
Which is close to what we have for C, plus the nullptr
syntax sugar. The behavior of operator ==
is defined by:
In addition, pointers to members can be compared, or a pointer to
member and a null pointer constant. Pointer to member conversions
(4.11) and qualification conversions (4.4) are performed to bring them
to a common type. If one operand is a null pointer constant, the
common type is the type of the other operand. Otherwise, the common
type is a pointer to member type similar (4.4) to the type of one of
the operands, with a cv-qualification signature (4.4) that is the
union of the cv-qualification signatures of the operand types. [ Note:
this implies that any pointer to member can be compared to a null
pointer constant. — end note ]
That leads to conversion of 0
to a pointer type (as for C). For the negation operator:
The operand of the logical negation operator ! is contextually
converted to bool (Clause 4); its value is true if the converted
operand is true and false otherwise. The type of the result is bool.
That means that result of !p
depends on how conversion from pointer to bool
is performed. The standard says:
A zero value, null pointer value, or null member pointer value is
converted to false;
So if (p==NULL)
and if (!p)
does the same things in C++ too.
Related Topics
Why Does Glgetstring(Gl_Version) Return Null/Zero Instead of the Opengl Version
How to Get Process Handle from Process Id
Priority Queue with Limited Space: Looking for a Good Algorithm
Stl Map Containing References Does Not Compile
How to Generate Type Library from Unmanaged Com Dll
How Is Tr1::Reference_Wrapper Useful
What Do the C and C++ Standards Say About Bit-Level Integer Representation and Manipulation
How to Embed/Link Binary Data into a Windows Module
Is There a C++ Equivalent to Getcwd
Are Non Dereferenced Iterators Past the "One Past-The-End" Iterator of an Array Undefined Behavior
Linking Not Working in Homebrew's Cmake Since Mojave
Parse String Containing Numbers into Integer Array
Wrap Overloaded Function via Std::Function
Std::Thread::Join() Hangs If Called After Main() Exits When Using VS2012 Rc
How to Parse Mustache with Boost.Xpressive Correctly
How to Handle a Ctrl-Break Signal in a Command Line Interface