我有以下代码:
#include <stddef.h>
int main() {
struct X {
int a;
int b;
} x = {0, 0};
void *ptr = (char*)&x + offsetof(struct X, b);
*(int*)ptr = 42;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
最后一行执行对 的间接访问x.b。
该代码是根据任何 C 标准定义的吗?
我知道:
*(char*)ptr = 42;已定义,但仅定义了实现。ptr == (void*)&x.b我猜想访问ptrvia指向的数据int*不会违反严格的别名规则,但我不完全确定该标准保证了这一点。
我们有:
struct A {
int x;
int y;
} a;
Run Code Online (Sandbox Code Playgroud)
假如说:
offsetof(struct A, x) + sizeof(int) == offsetof(struct A, y)
Run Code Online (Sandbox Code Playgroud)
C 标准(即 C11)能保证这&a.x + 1 == &a.y是真的吗?
如果没有,主流编译器是否能保证这一点?
此外,假设满足等式,是否可以在没有UB 的a.y情况下访问的值?(&a.x)[1]
关于什么memcpy(&a.x+1, ...)?
编辑
访问a.ywith(&a.x)[1]确实是UB,至少对于 CLANG 来说是这样。请参阅用户 @NateEldredge 的示例。
条件运算符中使用的 VM 类型的 C 标准可能存在矛盾。认为:
int f(void) { return 42; }
Run Code Online (Sandbox Code Playgroud)
现在,下面的表达式的类型是什么?
1 ? 0 : (int(*)[f()]) 0
Run Code Online (Sandbox Code Playgroud)
它的值必须等于 NULL,但我不确定类型是什么。是int(*)[f()]一个指向大小为 VLA 的指针f()。f()但是,要完成此 VM 类型,必须评估大小表达式。问题是它属于三元运算符的一个分支,未进行评估。从6.5.15p4开始:
仅当第一个操作数与 0 比较时不等于 0 时,才会计算第二个操作数;仅当第一个操作数比较等于 0 时才计算第三个操作数
条件运算符的规则要求指针的组合是另一个分支6.5.15p60的类型:
...如果一个操作数是空指针常量,则结果具有另一操作数的类型;...
如何解决这个矛盾呢?可能的解决方案是:
int(*)[f()]-f()无论如何都会被评估int(*)[]- 数组类型不完整复合类型的规则表明这可能是 UB,但我不确定这些规则是否适用于这种情况。我寻找引用 C17 规范的答案,但即将推出的 C2X 的措辞也很好。
以下函数是否严格符合C99?
void foo(int a[static 0]) {
(void)a;
}
Run Code Online (Sandbox Code Playgroud)
GCC 和 Clang 都会发出有关使用零大小数组的警告,但我认为这个警告是不合理的。AFAIK,6.7.6.3p7告诉static关键字指示指针a应该指向至少零个元素,任何具有确定值的指针都可以轻松满足这一要求。
此外,在以下情况下是否可以调用这样的函数:
int i;
foo(NULL);
foo(&i);
foo(&i + 1);
Run Code Online (Sandbox Code Playgroud)