Recently I learned from user "chux" that it is legal to add 1
to an address that doesn't represent an array element. Specifically, the following provision in the standard (C17 draft, 6.5.6 ¶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.
makes it legal to write &var + 1
where var
is not representable as arr[i]
for some T arr[n]
where 0
≤i
<n
.
What are use cases for doing this? I found an example by Aaron Ballman (on the SEI CERT C Coding Standard website) who mentions "allocation locality". Without quoting his entire example, the essence seems to be that one can allocate space for multiple objects using a single call to malloc
, so that one can assign to them like this:
T1 *objptr1 = (T1 *)malloc(sizeof(T1) + sizeof(*objptr2));
*objptr1 = ...;
memcpy(objptr1 + 1, objptr2, sizeof(*objptr2))
Here is a toy example of mine:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
float obj2 = 432.1;
long *objptr1 = (long *)malloc(sizeof(*objptr1) + sizeof(obj2));
*objptr1 = 123456789L;
memcpy(objptr1 + 1, &obj2, sizeof(obj2));
printf("%ld\n", *objptr1); // 123456789
printf("%f\n", *(float *)(objptr1 + 1)); // 432.100006
return 0;
}
I hope that this captures the essence of the idiom. (Perhaps it does not: As a commenter pointed out, my toy example assumes that the alignment of float
is smaller than or equal to the alignment of long
. The original example by Aaron Ballman had a string as the second object, and strings can be arbitrarily aligned. For a correct minimal (toy) version of Aaron Ballman's code stub see my own answer here.)
However, it seems that one could also simply use a (char *)
-cast with sizeof
instead:
memcpy((char *)objptr1 + sizeof(*objptr1), &obj2, sizeof(obj2));
In the general case, &var + 1
is shorter than (char *)&var + sizeof var
, so perhaps this is the advantage.
But is that all? What are use cases for writing (&var + 1) if var is not an array element?