Basically ptr + integer requires the compiler to determine the sizeof ptr's type.
Basically ptr + integer requires the compiler to determine the sizeof ptr's type.
No. From 6.5.6 Additive operators:
7 For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
8 [...] if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object [...] If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.
So &arr + 2 can overflow, and &arr + 1 cannot be dereferenced, but &arr + 1 shall not overflow and is not undefined behaviour.
Dereferencing the pointer is UB, but you can create the pointer, assign it to a variable, etc.
So &arr behaves like it's a pointer to the start of int[5][1].
> If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow;
this point doesn't apply to &arr + 1.
Likewise, the compiler ensures that you can build &arr[5] and that is the same address as &arr+1. &arr+1 cannot overflow.
if you're on a 16bit system and you define char x[36], the compiler guarantees that x's address is not more than 65500. if you do &x + 1 then you'll overflow, x + 1 won't.
You can pass whatever you want to the functions and apply the operands you want and the compiler will happily comply with you. But when you pass it 65500 and add 72 to it, it's going to overflow.
char *p = x;
p += 36; // overflow?
As arr == &arr, so are pointers P and Q that point just after last array item (1+&x[35]) and just after entire array (1+&x). As 6.5.6.8 above said, P is okay, and so must be Q. They said about last element, not second. Can you please explain why is x+1 even an argument?>if you're on a 16bit system and you define char x[36], the compiler guarantees that x's address is not more than 65500 65499?
This is 6.3.6 "Additive operators" in ISO C90 standard, for anyone curious.
> They also have a provision where a pointer to a nonarray value is treated as if it were a 1-element array
That is not what it says. Let me quote the exact words (emphasis mine):
For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
You're right that what we have is obviously (a pointer to) an array object, not an element of another array. This is precisely the case where this special provision kicks in, and thus it is legal to do &arr + 1.
I used to prefer C89 but learned the hard way that there are quite a few "bugs" in the standard, where it is ambiguous or otherwise fails to give a clear answer. So C99 is my go-to standard these days, even though I only care for a subset of its features.
"nonarray object" definitely sounds like such a bug. I think the intent of this clause is clear: it is meant to make sure you can always pass a pointer to a single object that treats its argument as a pointer to an array element, and does pointer arithmetic on it. One of the most common construct is simply looping over an array by incrementing the pointer, and this must work without producing an overflow when the pointer points past the array, the way it's conventionally written. If it weren't for this clause, passing a pointer to a single object to be treated as an array of size 1 would break a lot of code. Going further, is the object allocated by malloc an array or a nonarray? That would then be a critical question to ascertaining the correctness of most code out there.
And I cannot think of any reason why only pointers to nonarray objects should be usable in this manner.
Edit: Also now that I think about it, I've written code that relied on that behavior...not sure if I'd heard it before and internalized and forgot it, or just was being foolish.
So an implementation that could stick an array at the very end of the address space, and do wraparound for one-past-the-end so that it's represented by all bits zero, would then need to special-case that zero value when performing any pointer comparisons.
But yes, you'd need logic for pointer comparisons as well.
But, so far as I can see, this case (allocating at the very end of address space) is the only one where wraparound would matter for pointers.
And what would be the other option? If it's saturation, then your one-past-the-end pointer for the array at the end of address space would compare equal to pointer to last element...
Now, runtimes are increasingly adopting address randomization, which can change the rules about this, depending on what you are doing.