小编tst*_*isl的帖子

使用offsetof访问结构体成员

我有以下代码:

#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*不会违反严格的别名规则,但我不完全确定该标准保证了这一点。

c struct offsetof language-lawyer

14
推荐指数
1
解决办法
1197
查看次数

结构内的指针算术和比较

我们有:

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 的示例。

c struct pointers language-lawyer c11

9
推荐指数
1
解决办法
497
查看次数

`1 是什么类型?0 : (int(*)[f()])0`?

条件运算符中使用的 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 的措辞也很好。

c arrays language-lawyer variable-length-array

7
推荐指数
1
解决办法
140
查看次数

`void foo(int a[static 0]);` 有效吗?

以下函数是否严格符合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)

c c99 language-lawyer

4
推荐指数
2
解决办法
118
查看次数