struct {
int a;
int b;
} foo1 = {0, 0};
(&foo1.a)[1] = 1;
printf("%d", foo1.b);
struct {
int arr[1];
int b;
} foo2 = {{0}, 0};
foo2.arr[1] = 1;
printf("%d", foo2.b);
C11 § 6.7.2.1的第14段似乎表明这应该是实现定义:
结构体或联合体对象的每个非位域成员都以适合其类型的实现定义方式进行对齐。
后面又继续说道:
结构体对象内部可能存在未命名的填充,但不会出现在开头。
然而,像下面这样的代码似乎相当普遍:
union {
int arr[2];
struct {
int a;
int b;
};
} foo3 = {{0, 0}};
foo3.arr[1] = 1;
printf("%d", foo3.b);
(&foo3.a)[1] = 2; // appears to be illegal despite foo3.arr == &foo3.a
printf("%d", foo3.b);
这个标准似乎保证了
foo3.arr
与&foo3.a
相同,但从一个角度引用它是合法的,而从另一个角度引用却不合法,这是没有道理的。同样地,将外部结合体与数组相加后,使(&foo3.a)[1]
变得合法也是没有意义的。所以我认为第一个例子也一定是合法的:
foo3.arr
保证与&foo.a
相同foo3.arr + 1
和&foo3.b
指向同一内存位置&foo3.a + 1
和&foo3.b
因此必须指向同一内存位置(来自1和2)- 结构布局必须是一致的,因此
&foo1.a
和&foo1.b
应该与&foo3.a
和&foo3.b
完全相同 &foo1.a + 1
和&foo1.b
因此必须指向同一内存位置(来源于3和4)
foo3.arr[1]
和(&foo3.a)[1]
这两个例子都是不合法的,但是我无法找到标准中明确说明的语句来证明其不合法。即使它们都是不合法的,也可以使用灵活的数组指针构造相同的情况,这在我看来具有标准定义的行为。union {
struct {
int x;
int arr[];
};
struct {
int y;
int a;
int b;
};
} foo4;
原始应用程序正在考虑一个结构体字段的缓冲区溢出是否严格符合标准:
struct {
char buffer[8];
char overflow[8];
} buf;
strcpy(buf.buffer, "Hello world!");
println(buf.overflow);
我希望这段代码在几乎所有真实的编译器上输出"rld!",但是这种行为是否由标准保证,还是未定义或实现定义的行为?
foo.arr[1] = 1;
是未定义行为,没有规范说明下一个成员是foo.arr[1]
。 - chux - Reinstate Monica