Many beginners and even seasoned professional programmers seem to think that pointers are integers on some level. It is counterproductive and incorrect to think this way. The problem probably stems from people either using their favourite compiler and examining the resulting assembly language or having experience with assembly language prior to learning C and then forming preconceived notions about how C works. When someone refers to “the machine” in the context of talking about C, it is a fairly reliable indicator that bullshit is ensuing. My previous post probably be read before this one.
The C standard does allow you to convert between integers and pointers, which already illustrates that they’re not the same thing. Furthermore, there are several issues with converting pointers to integers1:
- Pointer to integer conversions are implementation-defined.
- If the result of a pointer to integer conversion is out of range, the behavior is undefined.
- There is no requirement for the result of a pointer to integer conversion to be in range for any integer type.
There are also several issues with integer to pointer conversions2:
- Integer to pointer conversions are implementation-defined.
- The pointer might not be correctly aligned.
- The pointer might not point to an entity of the referenced type.
- The pointer might be a trap representation.
What this also means is that conversion from pointer to integer and back needn’t result in the original pointer value.
C, since C99, does provide
uintptr_t which have the property of being signed and unsigned integers respectively that any valid
void * can be converted to them and back again to
void * and the result will compare equal to the original pointer. However, these types are optional — an implementation needn’t provide them3.
If pointers are not integers, why can we add to and subtract from them?
You can only do this in certain ways. For example, you cannot add two pointers together (constraint violation)4 and you cannot subtract two pointers that don’t both point to elements of the same array object or one past the last element (undefined behavior)5.
Pointers in C can be considered indexes into arrays. Even when a pointer is pointing to a non-array object, e.g. an
int, pointer arithmetic behaves as though it’s a pointer to an array of length one with the type of the object as its element type6, e.g.
int in this case.
Incrementing a pointer,
p++, simply advances the pointer by one element in the array.
Finally, C uses the term “arithmetic types” for integer and floating types7. Arithmetic types and pointer types are collectively called “scalar types”8. Many operators require their operands to have arithmetic type and therefore do not work with pointers. These include the unary
- operators and the multiplicative operators (
%). All the bitwise operators require integer types.
Conversion from pointers to integers — C11 §220.127.116.11p6 ↩
Conversion from integers to pointers — C11 §18.104.22.168p5 ↩
uintptr_t and intptr_t — C11 §22.214.171.124p1 ↩
Cannot add two pointers — C11 §6.5.6p2 ↩
Undefined behavior pointer subtraction — C11 §6.5.6p9 ↩
Non-array objects treated as arrays — C11 §6.5.6p7 ↩
Arithmetic types — C11 §6.2.5p18 ↩
Scalar types — C11 §6.2.5p21 ↩