pablo1977
pablo1977

Reputation: 4433

Pointer to integer conversion in Standard C

I've read several questions in this web about this topic, but I still have doubts.

In Standard C we can read:

6.3.2.3.p.5: An integer can be converted to any pointer type. [...]
6.3.2.3.p.6: Any pointer type can be converted to an integer type. [...].

The omitted text (that would go in brackets [...]) just talks about the issues that could happen when conversion fails.

However my question is more general:

  1. I observe that the integer mathematical numbers are infinite as a set of values.
  2. Any integer type in C can represent only a finite subset of the integer mathematical values.
  3. In paragraphs 6.3.2.3.p5/p6 it seems that Standard C11 assumes that "every pointer value can be mapped to an integer mathematical value".
  4. Besides, the way in that C11 standard is redacted seems to suggest that only when this mathematical (or abstract) value cannot be represented in the intended integer type chosen by the developer, for any reason, is when the operation fails.

My question would be: is my interpretation in point (3.) correct?

On the other hand, when we define an array of type T having size N,
since we can make integer arithmetic on the positions of the array,
it results obvious that, at least at "local" level, in an array,
we have that the corresponding block of memory of the array behaves
the same way, arithmetically, than the set of numbers from 0 to N-1, say.

By defining arrays or allocated objects, we can be sure that, in C,
the memory addresses can be "locally" considered as arithmetically equivalent to a subset of integers.

However, this "local" behavior would not be enough to derive the conclusion
that the Standard C assumes a memory model whose memory addresses can be considered as part of "only one and the same set of integer numbers".

However, 6.3.2.3.p5/p6 seems to "suggest" this stronger assertion, although I'm not completely sure.

An additional question could be bring more light:

Upvotes: 0

Views: 1609

Answers (3)

John Bollinger
John Bollinger

Reputation: 180093

It's odd that you disregard parts of the standard as "just talks about the issues that could happen when conversion fails" when some of those are exactly the parts that address your question.

  1. I observe that the integer mathematical numbers are infinite as a set of values.

True, but irrelevant. The standard says "any pointer type can be converted to [any] integer type" (emphasis added). It is referring specifically to a family of C data types, including, but not limited to, int. The text you omitted from your quote makes clear that some integer types might not be able to represent the result. In fact, it says "The result need not be in the range of values of any integer type" (emphasis added).

  1. Any integer type in C can represent only a finite subset of the integer mathematical values.

True.

  1. In paragraphs 6.3.2.3.p5/p6 it seems that Standard C11 assumes that "every pointer value can be mapped to an integer mathematical value".

No, as a matter of fact not. Part of the text you omitted was that "the result is implementation-defined" for conversion in both directions, with certain exceptions. The implementation-defined behavior of such a conversion could be that the program exits. I'd accept that the standard suggests that there may be a mapping or mappings such as you describe, but not that it assumes there is one.

  1. Besides, the way in that C11 standard is redacted seems to suggest that only when this mathematical (or abstract) value cannot be represented in the intedend integer type choosen by the developer, for any reason, is when the operation fails.

The operation never fails. Under many circumstances the behavior is implementation-defined, and under some it is undefined, but that's altogether different.

Note, however, that the standard places more requirements on implementations that choose to provide the optional intptr_t and/or uintptr_t types, as these support round-trip, value-preserving void * to integer type to void * conversions. Such implementations (which are typical) must have a 1-1 mapping from all possible pointer values not only to mathematical integers but to representable integer values.

Upvotes: 5

fuz
fuz

Reputation: 92966

My question would be: is my interpretation in point (3.) correct?

The standard specifies the types uintptr_t and intptr_t such that each valid pointer can be converted to an uintptr_t / intptr_t and back again. Compare ISO 9899:2011 §7.20.1.4:

7.20.1.4 Integer types capable of holding object pointers

1 The following type designates a signed integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:

intptr_t

The following type designates an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:

uintptr_t

These types are optional.

These types may not exist though, in which case no guarantee exists that each pointer maps to an integer.

Is open in standard C the possibility that two different valid pointers p, q, (that is: p != q), when converted to an integer type, the resulting integer values become equal.

Yes, this can happen. Consider a platform like 8086 with 20 bit pointers and 16 bit int. Obviously, when converting pointers to integers, many pointers are going to be mapped to the same integer. If you take a larger type, like a 32 bit long, then you get a unique value for each pointer though.

Upvotes: 2

user3386109
user3386109

Reputation: 34829

The answer to your p != q question is given in the [...] part of paragraph 6:

If the result cannot be represented in the integer type, the behavior is undefined.

Hence, if p and q are two different valid pointers, and you convert those pointers to integers without invoking undefined behavior, then the resulting integers will not compare equal.


The answer to your main question is given in note 67 (which applies to paragraph 5):

The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment.

In every execution environment that I'm aware of, the addressing structure is based on a finite subset of the natural numbers, with 0 being used as the NULL pointer. So converting from a pointer to an integer type is guaranteed to succeed if the range of integer values exceeds the range of addresses being used in the target hardware.

Upvotes: 1

Related Questions