5

I came across this function:

    int foo(int *p)
    {
      return p - (int*)0;
    }

Can someone explain what this does? It seems to return an integer. What's the logic behind this subtraction a null pointer? Also there was a comment that this is a pure and re-entrant function.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
nupadhyaya
  • 1,909
  • 1
  • 14
  • 14
  • That looks pretty random. It is not even subtracting the value, just moving the offset by a pointer to the int 0. – Chris Chambers May 22 '13 at 17:25
  • Here is explanation http://stackoverflow.com/questions/8128168/is-the-behavior-of-subtracting-two-null-pointers-defined – fasked May 22 '13 at 17:25
  • 1
    It's returning the int value of the pointer. Of course if the pointer is larger than an int truncation will occur. – Hot Licks May 22 '13 at 17:33
  • Did `(int*)0` appear like that in the source code, or was it a user-defined macro? If it was a macro like `ROM_BASE`, the above could make a lot more sense than if it was a literal zero. – supercat Oct 18 '18 at 17:42

3 Answers3

9

It has undefined behaviour, since pointer arithmetic is only defined within an array.

In practice, on a machine that represents pointers by a numerical address, and with sufficiently large integers, and a null pointer represented by address zero, it will convert a byte address into a word address. That is, it gives the number of int-sized lumps of memory between the null pointer's address and the address p.

Also there was a comment that this is a pure and re-entrant function.

"Pure" means that it has no side-effects, and the result only depends on its inputs. "re-entrant" means that it's safe to call while it's already in progress (for example, from an interrupt handler) - it has no internal static data.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • 2
    @larsmans: It's not subtracting zero, it's subtracting a null pointer. – Mike Seymour May 22 '13 at 17:29
  • Is it any more "undefined" (if that makes sense) than casting the pointer to `uintptr_t` directly? – user541686 May 22 '13 at 17:30
  • Ok so it returns the number of memory location b/n address 0 and address p.Oh k thans man... – nupadhyaya May 22 '13 at 17:32
  • 1
    @Mehrdad: That would give a different value; probably the *byte* offset from zero, not the *word* offset. – Mike Seymour May 22 '13 at 17:32
  • 2
    @Mehrdad Yes, casting to `uintptr_t` is not undefined behaviour at all. The result is implementation-defined, but there's no UB in that. – Daniel Fischer May 22 '13 at 17:32
  • 1
    @Mehrdad: But yes, `(uintptr_t)p / sizeof(int)` would be "more" defined (as long as `uintptr_t` exists): implementation-defined with a note that the mapping "is intended to be unsurprising to those who know the addressing structure of the underlying machine." – Mike Seymour May 22 '13 at 17:42
0

Subtracting two pointers returns an integer of type ptrdiff_t, the offset between two pointers, in units of sizeof(int). Whether that can be validly cast to int is implementation-dependent. Subtracting a null pointer causes undefined behavior.

This seems to be a complicated and unreliable way of converting a pointer to an integer. A better way is to cast it to intptr_t and divide by sizeof(int).

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
0

I would guess that the person who wrote that function thinks they're more clever than they really are. It does nothing that a simple cast wouldn't do better.

As to "pure" and "reentrant"...

A pure function is one that's only effect is the return value. It causes no state change.

A reentrant function is thread safe. It can be interrupted and called by another thread without altering the effect of the original call.

All pure functions are reentrant.

The fact that it's a pure function is obvious, as is its reentrancy. The comment is pointless as well as the function itself.

Edward Strange
  • 40,307
  • 7
  • 73
  • 125