4

If I subtract two void pointers, I get the relative distance in bytes (at least on my test system I do) between the pointer locations. What type should I use to store the result in, such that it is compatible with 64-bit systems? Is size_t the correct type or perhaps long?

Background: we need to check whether a given void pointer is safe to be used as a double pointer. We used to cast the pointer to int and check that the lower three bits are zero, however our current coding standards do not allow casting pointers to integer types anymore. I am considering calculating the difference between the void pointer and the NULL pointer and checking whether that difference is dividable by 8. Assuming that the NULL pointer is always 8-byte aligned?

slingeraap
  • 484
  • 1
  • 5
  • 14

4 Answers4

7

Subtraction of void pointers is not defined in the C standard. Subtraction of pointers is only defined when they both point into the same array and a void pointer can't point into any array because you can't have an array with void elements.

Most likely you're using gcc or something compatible and it allows arithmetic on void pointers as an extension which it treats as char pointers. But a strict C compiler should not allow pointer arithmetic on void pointers.

Art
  • 19,807
  • 1
  • 34
  • 60
4

From C11, 6.5.6 Additive operators /9 (my italics):

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 <stddef.h> header.

By that section, it's also technically undefined behaviour to subtract NULL from a pointer since NULL can in no way be considered a pointer to an element of the same array, or one beyond it. Pointer subtraction is really limited to getting the index difference between two elements in the same array.

So you may want to reconsider this checking that you're doing, especially in light of the fact a double doesn't actually need to be eight bytes long and, even if it is, there's no requirement in the standard that it be aligned on an eight-byte boundary.

I'd be more inclined to just state in the documentation for your function that the value passed needs to be a valid double pointer and, if a user of your function violates that contract, all bets are off.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
4

If I subtract two void pointers, I get the relative distance in bytes (at least on my test system I do) between the pointer locations.

There is a strict rule to subtract two pointers. C11-§6.5.6:

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. [...]


what type is the difference of two void pointers?

It should be ptrdiff_t.

[...] The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. [...]

haccks
  • 104,019
  • 25
  • 176
  • 264
4

Summary of the problems:

  • You are confusing the null pointer constant macro NULL with null pointers. Those are two different terms. The NULL macro is always equivalent to 0, but a null pointer may have any value. See this.

  • That being said, it doesn't make any sense to do pointer arithmetic with null pointers nor with the NULL macro. Doing so would invoke undefined behavior, because the pointers have to point at the same array. See the answer by paxdiablo.

  • In addition, as noted in the answer by Art, you cannot do any form of arithmetic on void pointers. The + and - operators are specified as (6.5.6):

    For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type.

    A void pointer is a pointer to incomplete type, so if either or both operands are void pointers, your code is not valid C.

    Note that GCC has a non-standard extension which allows void pointer arithmetic, by treating void pointers as pointer-to-byte for such cases. Never use this non-standard feature if you intend to write safe and portable programs. Compile with gcc -std=c11 -pedantic-errors if you wish GCC to behave as a standard C compiler (conforming implementation).

Community
  • 1
  • 1
Lundin
  • 195,001
  • 40
  • 254
  • 396