Can we subtract NULL pointers?
Asked Answered
I

4

7

Since pointer arithmetic is defined within the same array I'm in doubt if we can subtract NULL from another NULL. I'm concerned about the implementation of:

//first and second can both either be from the same array 
//or be both NULL
prtdiff_t sub(void *first, void *second){
    //Do I really need this condition?
    if(!first && !second)
        return (ptrdiff_t) 0;

    return second - first;
}

Note: This question about C. If you are looking for C++ question, it is here (the answer is different!). There is also common question for both C and C++.

Isaac answered 18/4, 2019 at 13:59 Comment(13)
@HarshitAgrawal any reference would be highly appreciateIsaac
@Isaac Actually you have explained it yourself and likely have your reference ...Septicemia
Looks weird, because the case where only one is NULL is not handle.Telephotography
@Ôrel It is an artificial example to show the actual problem I'm concerned about.Isaac
Well, checking here for NULL has a little help as any other invalid pointer will break it equally.Septicemia
@Isaac while I was looking for references two answers posted. :pShied
@Isaac I think you misunderstood the concept of null and actually thought that null has a specific value.Shied
@HarshitAgrawal NULL is clearly defined as: An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. So I used to think that we could subtract one 0 from another 0...Isaac
@Isaac 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.Interurban
Even if NULL is defined as an integer 0, then after assigning char *a = NULL; char *b = NULL;, then the subtraction a - b is still illegal.Interurban
Also, you cannot subtract void * pointers to elements of the same array, because you cannot have an array of void. (Yes, I know GCC allows pointer arithmetic on pointers to void as an extension to the C language.)Interurban
@Isaac I have posted an answer below :p I was very slow in answering because I was trying to post the answer in simple language for future readersShied
It is an artificial example to show the actual problem I'm concerned about. In that case, please post a more realistic example. The code shown is broken, and not just when first and second happen to be NULL. (And yes, I know I'm a bit late with that observation).Gigolo
R
11

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.

Ridicule answered 18/4, 2019 at 14:3 Comment(8)
On many implementations the intptr_t difference would be a byte difference, but the result of converting a pointer to an integer is implementation-defined, so that result is not guaranteed.Cavorelievo
Technically NULL is a valid adress and is the first byte of addressable memory. Hence it can point to an array object and so you can subtract NULL from NULL. It s only the memory management hardware that has been told that for applications NULL is not a valid adress and upon dereferencing it should throw an exception. Example: interrupt vectors start at zero.Coition
@PaulOgilvie I believe NULL is defined not to be a valid address by the standard (reference needed..). The case on a specific architecture where the address 0 is actually valid (and having NULL representation the same as pointer to this address) is making the corresponding architecture/toolchain combo non-compliant.Septicemia
@EugeneSh., ... interesting. It means you cannot have code written in C that modifies the interrupt vector at address zero.Coition
@PaulOgilvie Here is the citation: port70.net/~nsz/c/c11/n1570.html#6.3.2.3p3 ..the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.. But yeah, that would be one of these corner cases where you just say "well, my compiler is sane enough to understand what I want to do"..Septicemia
@PaulOgilvie: Semantically, the null pointer value is only guaranteed to compare unequal to the address of any object or function. It is not guaranteed to be address 0 (some older systems used 0xDEADBEEF as the null pointer value). It is also considered an invalid pointer value (the behavior on attempting to dereference it is undefined).Anybody
@JohnBode, thanks: It is not guaranteed to be address 0 is the key.Coition
@PaulOgilvie c-faq.com/null/null1.html c-faq.com/null/varieties.html You can't have portable code written in C that modifies addresses at arbitrary locations. I remember reading that casting integer types to pointers is implementation-defined.Cultivator
T
7

No you can't do this: the difference between two pointers is only defined for pointers that point to elements of the same array, or one past the end. (For this purpose an object counts as a single element array).

(intptr_t)second - (intptr_t)first is valid though.

Trawl answered 18/4, 2019 at 14:2 Comment(3)
The integer difference is definitely valid, but its meaning is implementation-defined (provided there is no overflow), on account of the result of converting pointers to integers being implementation defined.Cavorelievo
@JohnBollinger Implementation-defined in the sense of intptr_t is not required to be supported? Or in some another way?Isaac
As I said, @St.Antario, implementation-defined because the effect of converting a pointer value to an integer type is implementation-defined, regardless of the particular integer type involved. That intptr_t is optional is a separate issue.Cavorelievo
S
0

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.

But there is no such provision for C.

Somnifacient answered 18/4, 2019 at 14:5 Comment(4)
So C++ handles your case.Telephotography
This question is tagged C, not C++.Ridicule
If you add something like "..but there is no such a provision for C" and a conclusion, your answer might become considered as good one.Septicemia
@dbus I was looking for the same question but about C++. Unfortunately Google by default provides link only to this (pure C) question. I skipped this answer because it is downvoted and thought that subtracting null pointers is not valid in C++ either. But it is wrong. This is misleading. This answer is what I really needed. But it is downvoted. It is frustrating. Anyway there is similar question about C++.Gettings
S
-1

The simple answer is NO, YOU CAN'T SUBTRACT A NULL FROM ANOTHER NULL.

I think you misunderstood this definition:

NULL is clearly defined as: An integer constant expression with the value 0, or such an expression cast to type void, is called a null pointer constant. So I used to think that we could subtract one 0 from another 0.

Now, As for now let's take GOOGLE's Definition of NULL

Null means having no value; in other words null is zero, like if you put so little sugar in your coffee that it's practically null. Null also means invalid. From the Latin nullus, meaning "not any," poor, powerless null is not actually there at all.

Clearly, it states that null has no value. Think of it as you are trying to subtract nothing from nothing.

Now let's take it in other words, null is zero (if and only if defined value) you can subtract it for sure (but not you can do something like char *ab = NULL, char *aa= NULL and then performing subtraction like ab-aa is still illegal)

But no one can actually predict the value for null so, when you are unable to get the value you are not able to perform any operation(like subtraction, addition, etc.) on that.

Shied answered 18/4, 2019 at 14:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.