-4

Why does

printf("%ld\n", (void *)0 - (void *)0);

compile, but

printf("%ld\n", (void *)0 + (void *)0);

does not?

Chris
  • 26,361
  • 5
  • 21
  • 42
Sapphire_Brick
  • 1,560
  • 12
  • 26
  • 6
    What would a sum of pointers mean? – bereal Jan 14 '22 at 17:13
  • 1
    [Checkthis](https://stackoverflow.com/questions/36615981/c-what-type-is-the-difference-of-two-void-pointers#:~:text=Subtraction%20of%20pointers%20is%20only,an%20array%20with%20void%20elements.) – THUNDER 07 Jan 14 '22 at 17:14
  • 2
    You can add an integer to a pointer. However, pointer arithmetic on `void *` is a GNU C extension that is not part of the C standard. The C standard only supports pointer arithmetic on pointers to *complete* object types, and `void` is an *incomplete* object type by definition. – Ian Abbott Jan 14 '22 at 17:14
  • @bereal Treat them as numbers, and add them. – Sapphire_Brick Jan 14 '22 at 17:14
  • 2
    As bereal said: `What would a sum of pointers mean?` Specifically: 1) an "address" is the sum of a pointer and an offset. 2) An "offset" is computed by subtracting pointers. 3) "Adding" two pointers, however ... is nonsense. – paulsm4 Jan 14 '22 at 17:16
  • @FredLarson I would expect that `(void *)p + NULL` would yield `(void *)p`, at the very least. – Sapphire_Brick Jan 14 '22 at 17:18
  • _Treat them as numbers_ What does this mean? – Language Lawyer Jan 14 '22 at 17:20
  • @LanguageLawyer In the same way that `(int)1 + (int)2` = `(int)3`, `(void *)1 + (void *)2` should yield `(void *)3`. – Sapphire_Brick Jan 14 '22 at 17:22
  • What if a pointer was not obtained by `(void*)#number`? – Language Lawyer Jan 14 '22 at 17:23
  • @LanguageLawyer Why should other pointers be different? I mean, `p + (void *)1` should be equivalent to `p + 1` and `p + q` should be equivalent to `p + (size_t)q`. – Sapphire_Brick Jan 14 '22 at 17:27
  • 3
    @Sapphire_Brick *`p + (void *)1` should be equivalent to `p + 1` and `p + q` should be equivalent to `p + (size_t)q`.* Huh? **Why** "should" they be equivalent to that? An address plus an address is nonsense. An address is **where something is**. How do you even represent the arithmetic addition of two **locations**? "When we add 123 Main St to 43 Third St, where are you?" – Andrew Henle Jan 14 '22 at 17:33
  • @AndrewHenle Fair enough, but shouldn't `NULL` at least coerce to a `ptrdiff_t`? – Sapphire_Brick Jan 14 '22 at 17:36

2 Answers2

2

For starters this expression

(void *)0 - (void *)0

has undefined behavior because according to the C Standard (6.5.6 Additive operators)

3 For subtraction, one of the following shall hold:

— both operands are pointers to qualified or unqualified versions of compatible complete object types;

The type void is an incomplete type.

You could write for example

(char *)0 - (char *)0

Some compilers for backward compatibility have their language extensions that allow such an operation for pointers of the type cv void *.

As for the operator + then it is just not defined for pointers. For this operator applied to pointers this shall be satisfied

2 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.

Applying the operator + for pointers does not make a sense.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

It is useful to find the difference between two pointers. This gives an integer (a ptrdiff_t).[1]

It is useful to add a difference to a pointer, so we can add an integer to a pointer (and vice-versa). The inverse operation of ptrdiff = p2 - p1 is p2 = p1 + ptrdiff.[1]

However, there's no sensible meaning to adding two pointers together. So that's not allowed.


  1. Note that this is undefined behaviour for void * pointers, and for pointers that aren't to parts of the same object.
ikegami
  • 367,544
  • 15
  • 269
  • 518