结构内的指针算术和比较

tst*_*isl 9 c struct pointers language-lawyer c11

我们有:

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

Eri*_*hil 7

是的。C 2017 6.5.9,其中讨论了==!=,说:

\n
\n

6 两个指针比较相等当且仅当两个指针都是空指针,都是指向同一个对象(包括指向对象的指针和其开头的子对象)或函数的指针,都是指向同一对象的最后一个元素之后的指针数组对象,或者一个是指向一个数组对象末尾的指针,另一个是指向恰好紧随地址空间中第一个数组对象的另一个数组对象的开头的指针。

\n

7 就这些运算符而言,指向不是数组元素的对象的指针的行为与指向长度为 1 的数组的第一个元素的指针相同,且对象的类型作为其元素类型。

\n
\n

根据第 7 段,a.x每个a.y都充当 1 的数组int,用于 的目的==

\n

由于offsetof(struct A, x) + sizeof(int) == offsetof(struct A, y)保证地址空间中a.y紧随其后,a.x&a.x+1 == &a.y满足第 6 段中的最后一个条件,即一个是指向一个数组对象末尾的指针,另一个是指向紧随第一个数组对象的另一个数组对象的指针。

\n
\n

此外,假设满足等式,是否可以在没有UB 的a.y情况下访问的值?(&a.x)[1]

\n
\n

&a.x+1 不。等于 的事实&a.y并不意味着它 &a.y

\n

标准中没有完整或明确地说明这一点。在某些情况下,指针算术必须能够遍历内存中相邻的对象,特别是结构成员。例如,如果我们将指向结构的指针转换为 a char *,我们可以使用它来访问结构中的各个字节。我们可以用它来遍历整个结构,包括成员。然后,如果我们适当地增加它以指向某个成员并将其转换回指向该 member\xe2\x80\x99s 类型的指针,我们应该有一个指向该成员的指针。

\n

然而,C 标准是用自然语言编写的,并不完全用形式逻辑或数学的表示法(尽管有一些),所以它是不完整的,我们并不总是确定它指定了什么。由于它没有告诉我们&a.x + 1可以用来访问a.y,因此该行为因遗漏而未定义。

\n

  • 有趣的是,这是否意味着如果我们有 `struct A { int x; 整数y;整数 z; }` 并且我们知道 `offsetof(struct A, x) + sizeof(int) * 2 == offsetof(struct A, z)` - 那么 `&a.x + 2 == &a.y` 将是未定义的? (2认同)