1

Related to: Three questions: Is NULL - NULL defined? Is (uintptr_t)NULL - (uintptr_t)NULL defined?

Lets consider:

  1. Case 1: (uintptr_t)NULL - (uintptr_t)NULL will the result always be zero?

  2. Case 2 (ispired by the Eric comment):

uintptr_t x = (uintptr_t)NULL;

will x - x be always zero?

  1. case 3:
uintptr_t x = (uintptr_t)NULL, y = (uintptr_t)NULL;

Will x-y be always zero?

  1. Case 4:
void *a; 

/* .... */

uintptr_t x = (uintptr_t)a, y = (uintptr_t)a;

Will x-y be always zero?

If not - why?

0___________
  • 60,014
  • 4
  • 34
  • 74
  • 1
    Do you ask theoretically or practically? Because I can write a compiler, and document that on in my custom compiler "the expression NULL - NULL is equal to 0, except when on line 12, then it's equal to 62" and it still will be "implementation defined" (just insane). If such compiler can still reach a conforming behavior of the program (ie. it will track which pointers where converted on which line within the pointer value), then it could be fine. – KamilCuk Nov 08 '20 at 17:39
  • @KamilCuk do it ! :D – Cid Nov 08 '20 at 17:40
  • @KamilCuk do you know what "language-lawyer" tag mean? – 0___________ Nov 08 '20 at 20:09

2 Answers2

2

Can two implementation defined identical expressions give different results?

Yes. It's "implementation-defined" - all rules are up to implementation. An imaginary implementation may look like this:

int main() {
      void *a = 0;
#pragma MYCOMPILER SHIFT_UINTPTR 0
      printf("%d\n", (int)(uintptr_t)a); // prints 0
#pragma MYCOMPILER SHIFT_UINTPTR 5
      printf("%d\n", (int)(uintptr_t)a); // prints 5
}

Still such an implementation would be insane on most platforms.

I could imagine a example: architecture that has to deal with memory in "banks". A compiler for that architecture uses a #pragma switch to select the "bank" that is used for dereferencing pointers.

  1. (uintptr_t)NULL - (uintptr_t)NULL will the result always be zero?

Not necessarily.

  1. will x - x be always zero?

Yes. uintptr_t is an unsigned integer type, it has to obey the laws of mathematics.

  1. Will x-y be always zero?

Not necessarily.

  1. Will x-y be always zero?

Not necessarily.

If not - why?

The result of conversion from void* to uintptr_t is implementation defined - the implementation may convert the pointer value to different uintptr_t value each time, which would result in a non-zero difference between the values.

I could see a example: on some imaginary architecture pointers have 48-bits, while uintptr_t has 64-bits. A compiler for such architecture just "doesn't care" what is in those 16 extra bits and when converting uintptr_t to a pointer it uses only the 48-bits. When converting pointer to an uintrpt_t compiler uses whatever garbage value was leftover in registers for the extra 16-bits, because it's fast to do that in that specific architecture and because they will never be used when converting back..

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • (int)(uintptr_t) is not something I am asking about.# – 0___________ Nov 08 '20 at 19:55
  • `#pragma MYCOMPILER SHIFT_UINTPTR 5 printf("%d\n", (int)(uintptr_t)a); // prints 5` and `#pragma MYCOMPILER SHIFT_UINTPTR 0 printf("%d\n", (int)(uintptr_t)a); // prints 0` are two distinct expressions. They are not the same. – 0___________ Nov 08 '20 at 20:03
0

You won't find a system in use anywhere where NULL isn't defined as some form of 0, be it the literal value or a void * with value 0, so all of your checks will either work as you'd expect or be syntax errors (can't subtract void * values).

Is it possible to be defined as anything else though? Theoretically. Though it's still a constant, so subtracting them (language and type allowing) will still equal 0.

Blindy
  • 65,249
  • 10
  • 91
  • 131
  • I am not asking about the implementations. The question is about the **C standard**. Read the tags – 0___________ Nov 08 '20 at 19:58
  • `You won't find a system in use anywhere where NULL isn't defined as some form of 0` ny_killer_compiller : `#define NULL -1`. Now you have an implementation – 0___________ Nov 08 '20 at 20:12
  • 1
    @P__JsupportswomeninPoland _`#define NULL -1`. Now you have an implementation_ Which is not conforming. – Language Lawyer Nov 09 '20 at 06:51
  • 2
    _You won't find a system in use anywhere where `NULL` isn't defined as some form of `0`._ Possibly not now, but did you see the [When was the NULL macro not 0?](https://stackoverflow.com/questions/2597142/when-was-the-null-macro-not-0) thread? It does not conform current standards, which require null pointer to yield zero when cast to integral types. However, the latter applies to integral _conversion_ only, the internal representation of the null pointer needn't be zero-bytes only. – CiaPan Jun 10 '21 at 15:24
  • The C standard has never allowed something like `#define NULL -1`.Maybe on some platforms `NULL` (defined as a `void*` value) has the same bit pattern as `-1` (an `int` value), but `#define NULL -1` is still non-conforming. – F.v.S. Jul 13 '22 at 04:16
  • @F.v.S. [Even in C89?](https://port70.net/~nsz/c/c89/c89-draft.html) Integer constant expressions, cast to `void *` or not, would merely be a "null pointer constant" and do not restrict the definition of `NULL`. That does not preclude `NULL` being defined to something with a non-zero value, such as `#define NULL -1`, and I can't find any other text in C89 that limits `NULL` to a zero-defined value. – Andrew Henle Sep 06 '22 at 23:23
  • @AndrewHenle `NULL` is already required by C89 to expand to an implementation-defined null pointer constant. And it's required in C89 that "An integral constant expression with the value 0, or such an expression cast to type `void *`, is called a null pointer constant." So `-1` can never be a null pointer constant. – F.v.S. Sep 09 '22 at 03:29
  • @F.v.S. "An integral constant expression with the value 0, or such an expression cast to type `void *`, is called a null pointer constant."? That does not state, limit, or in any way preclude an implementation from defining `-1` to **also** be a null pointer constant. "All vehicles in the US must drive on the right side of the road" does not preclude vehicles in the UK from driving on the left side of the road. – Andrew Henle Sep 09 '22 at 10:33
  • @AndrewHenle This sentence is the **definition** of null pointer constant, so it does state, limit, and preclude defining `-1` to be a null pointer constant. – F.v.S. Sep 09 '22 at 13:22
  • @F.v.S. Wrong. All that does is state that integer constants with a value of zero are in the set of null pointer constants. It in no way precludes other values being in that set. How does saying "Integer constants with a value of zero are null pointer constants" do **anything** to preclude "An integer constant with a value of -1 is also an implementation-defined null pointer constant"? Saying "Zero is a number" does not mean "all numbers must be zero". – Andrew Henle Sep 09 '22 at 14:06
  • @AndrewHenle The "null pointer constant" in that sentence is italic-styled in the published standard (the style is lost in the HTML draft), so the sentence must be read as a definition. – F.v.S. Sep 09 '22 at 14:45