Question Details

No question body available.

Tags

c language-lawyer undefined-behavior pointer-arithmetic

Answers (5)

Accepted Answer Available
Accepted Answer
September 2, 2025 Score: 4 Rep: 236,527 Quality: Expert Completeness: 60%

The C behavior for pointer arithmetic is defined in terms of the object that the pointer points to. It has nothing to do with the identifier that names the object.

In C, what people commonly call a variable is an identifier combined with an object. int c = 0; defines a variable with the name (identifier) c and memory for an int (an object). However, you can have objects with no identifiers (malloc provides memory in which you can create objects, using pointers), and you can have identifiers that do not refer to objects (a name might refer to a type or a function or something else).

The rules for pointer arithmetic, in C 2024 6.5.7, are entirely defined in terms of the pointed-to object (an array element and the array it is in). In this code:

int p = malloc(10  sizeof p);
for (int i = 0; i < 10; ++i)
    p[i] = ii;
int *q = p + 3;

the p + 3 is defined because p points to an element in an array of 10 int, even though that array has no name. (p points into the array, but there is no identifier for the array itself).

If one translation unit receives a pointer from another translation unit, all that matters for pointer arithmetic is whether the pointed-to object satisfies the requirements of pointer arithmetic. Whether names are known or even exist is irrelevant.

Further, the rules for pointer arithmetic say nothing about whether any information about the objects is present in the translation unit containing the arithmetic. If one translation unit creates an object, and another translation unit performs defined arithmetic on pointers related to that object, the C implementation must make the arithmetic work.

September 2, 2025 Score: 9 Rep: 234,889 Quality: Medium Completeness: 40%

There is no problem performing pointer arithmetic on buf, as long as the result is in the range of buffer + 0 to buffer + 10.

C doesn't actively check whether any pointer arithmetic you perform results in something valid. That's part of what makes it fast. What the above passage from the standard is essentially telling you is not to go past the bounds of any array object.

September 2, 2025 Score: 4 Rep: 790,494 Quality: Medium Completeness: 50%

It's the programmer's responsibility to ensure that they don't go out of bounds, not the compiler's. Even in the same compilation unit, the compiler can't always tell the size of the object that a pointer points to, since it can be assigned conditionally:

int buffer1[10];
int buffer2[20];
int * buf;

if (somecondition) { buf = buffer1; } else { buf = buffer_2; }

Even more common are memory allocations using malloc(), where the size is dynamic and can change over time if you use realloc().

So it doesn't matter where the pointer comes from. Pointer arithmetic is defined as long as you stay within the actual object it points to. Whether the compiler can verify this is irrelevant.

September 2, 2025 Score: 4 Rep: 16,426 Quality: Medium Completeness: 60%

Perfectly fine to add offsets from 0..10 inclusively — that is, produce an expression of the pointer type pointing to any array element as well as one past the last element; and fine to read from the memory pointed to by the resulting pointer expression up to and including an offset of 9 — that is, from anywhere in the array but not past it.

There is an array there, which means your quoted point 9. does not apply; point 10. doesn't apply because it's not a single integer.

The reason for that funny provision that even just producing a pointer expression outside the array + 1 element even if we never read from that location is that funny architectures may produce an overflow — an illegal address — that traps when it occurs in a register. Typical architectures today don't do that any more though.

The rationale to allow an address that points one past the array is probably to facilitate simpler loops, e.g. for loops that break only when the address is already past the array. The implementation on a machine that may produce overflows is relatively easy: Just don't place an array (or variable) at the very end of a memory segment.

September 2, 2025 Score: 3 Rep: 72,712 Quality: Low Completeness: 10%

That is, formally, at the point of calling int *buf = getbufaddr(); the compiler does not know whether buf points to a single object (not an array) of type int, or to an array of such objects (and if to an array, how long is this array?).

Compiler does not have to know it. It is the programmer responsibility to keep the arithmetics in boudaries of an array + one after last lelemnt of an array.