Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the behavior of subtracting two NULL pointers defined?

Tags:

c++

c

c99

c89

Is the difference of two non-void pointer variables defined (per C99 and/or C++98) if they are both NULL valued?

For instance, say I have a buffer structure that looks like this:

struct buf {   char *buf;   char *pwrite;   char *pread; } ex; 

Say, ex.buf points to an array or some malloc'ed memory. If my code always ensures that pwrite and pread point within that array or one past it, then I am fairly confident that ex.pwrite - ex.pread will always be defined. However, what if pwrite and pread are both NULL. Can I just expect subtracting the two is defined as (ptrdiff_t)0 or does strictly compliant code need to test the pointers for NULL? Note that the only case I am interested in is when both pointers are NULL (which represents a buffer not initialized case). The reason has to do with a fully compliant "available" function given the preceding assumptions are met:

size_t buf_avail(const struct s_buf *b) {          return b->pwrite - b->pread; } 
like image 474
John Luebs Avatar asked Nov 14 '11 21:11

John Luebs


People also ask

What happens when you subtract 2 pointers?

The subtraction of two pointers gives the increments between the two pointers. For Example: Two integer pointers say ptr1(address:1000) and ptr2(address:1016) are subtracted. The difference between address is 16 bytes.

Can you subtract a null?

Antario So if NULL is defined as an integer constant expression you can subtract NULL from NULL , but not that is not portable because it might not be (and usually isn't) defined as an integer constant expression.

How is null pointer defined?

Null pointersA null pointer has a reserved value that is called a null pointer constant for indicating that the pointer does not point to any valid object or function. You can use null pointers in the following cases: Initialize pointers. Represent conditions such as the end of a list of unknown length.


1 Answers

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.

like image 85
Adam Rosenfield Avatar answered Sep 23 '22 02:09

Adam Rosenfield