【发布时间】:2018-01-08 09:29:17
【问题描述】:
结构中相同类型的连续成员之间的指针算术曾经是一种常见的做法,而指针算术仅在数组内部有效。在 C++ 中,这将是明确的未定义行为,因为数组只能由声明或新表达式创建。但是 C 语言将数组定义为一个连续分配的非空对象集 特定的成员对象类型,称为元素类型。(C11 的 n1570 草案,6.2.5 类型§20)。因此,如果我们可以确保成员是连续的(意味着它们之间没有填充),那么将其视为一个数组是合法的。
这是一个简化的示例,它编译时没有警告并在运行时给出预期的结果:
#include <stdio.h>
#include <stddef.h>
#include <assert.h>
struct quad {
int x;
int y;
int z;
int t;
};
int main() {
// ensure members are consecutive (note 1)
static_assert(offsetof(struct quad, t) == 3 * sizeof(int),
"unexpected padding in quad struct");
struct quad q;
int *ix = &q.x;
for(int i=0; i<4; i++) {
ix[i] = i;
}
printf("Quad: %d %d %d %d\n", q.x, q.y, q.z, q.t);
return 0;
}
这里没有真正的意义,但我已经看到了现实世界的例子,其中在结构成员之间进行迭代允许更简单的代码,减少拼写错误的风险。
问题:
在上面的例子中,static_assert 是否足以使结构与数组的别名合法化?
(注 1)由于结构 描述了一个顺序分配的非空成员对象集,后面的成员必须具有递增的地址。简单地说,编译器可以在它们之间包含填充。所以最后一个成员的偏移量(这里是t)如果3倍sizeof(int)加上它之前的总填充。如果偏移量正好是3 * sizeof(int),那么结构中没有填充
作为重复提出的问题既包含一个可以接受的答案,让我们认为它是 UB,也包含一个 +1 answer,让我们认为它可能是合法的,因为我可以确保不存在任何填充
【问题讨论】:
-
不,这是未定义的行为。
int x;是一个大小为 1 的数组。将联合与数组和你的结构一起使用......也许。 -
几天前我知道了这个并且它是UB(如果我没记错的话)。
-
@P.P:副本确实解决了类似的问题,但在这里我可以证明(在编译时)该结构不包含填充。副本中一个赞成的答案(仅+1)表示填充是问题所在。所以我接受要关闭的问题,但我想知道它是否是UB 当结构不包含填充时
-
只有一个+1的答案,说在struct有only一个成员并且没有填充的问题的情况下,这不会是UB.. .这不是你的情况,也不是你的代码的相同上下文,关键是编译器允许假设你永远不会使用
&q.x的一个元素,因为它是“一个大小为一的数组”,所以在你的您触发的代码越界。不应该是 UB 的联合示例,rextester.com/OLCE62527。 -
@SergeBallesta 问题不是,但问题的答案会回答你。这是同样的问题。并且对您的问题的回答将引用该标准的同一句话。
标签: c arrays struct language-lawyer