4 ms·
Yes &arr does behave like arr when it comes to ptr arithmetic but the compiler does not guarantee that &arr + 1 does not overflow. It only guarantees arr + 1. i
by halayli 10y ago
Yes &arr does behave like arr when it comes to ptr arithmetic but the compiler does not guarantee that &arr + 1 does not overflow. It only guarantees arr + 1. if you have a ptr from heap, ptr + 1 if not alloced previously is UB.
> 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.
- bonzini 10y agoHow so? If the array has five elements, you can pass &arr to a function that expects an int[5][], and that function certainly can build a pointer that points one past the last element. Likewise, the compiler ensures that you can build &arr[5] and that is the same address as &arr+1. &arr+1 cannot overflow.
- halayli 10y agoThe compiler guarantees that arr + 1 doesn't overflow by making sure arr's address is small enough to not overflow when accessing one element past the array size. &arr + 1 is not one past the array you asked the compiler to allocate. 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.
- clarry 10y agoThen you have a broken compiler.
- wruza 10y agoWait, wait. 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?
- int_19h 10y agoNo, he is correct. The C and C++ standards do allow pointers past the last element of an array to be produced via a pointer to an element of said array. They also have a provision where a pointer to a nonarray value is treated as if it were a 1-element array (so you can do "int x; int* p = *x + 1"). But in this case, the value is obviously an array object, and it's not an element to another array; hence, it is not legal to do &arr + 1 ("... otherwise, the behavior is undefined"). This is 6.3.6 "Additive operators" in ISO C90 standard, for anyone curious.
- clarry 10y agoNo, he isn't correct. > 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.
- int_19h 10y agoIt looks like we're quoting different standards (or different versions of them). I was referring to ISO C90, which specifically says "nonarray object". I guess yours is C99 or C11?
- clarry 10y agoI quoted from C99 but C11 has the same wording. 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.