在C语言中,能否将一个双精度浮点型结构体强制转换为一个双精度浮点型数组?

4
这在C语言中是否合法?
struct Doubles
{
  double a,b,c;
};

void foo(struct Doubles* bar)
{
  double* baz = (double*)bar;
  baz[0]++;
  baz[1]++;
  baz[2]++;
}

我知道它在MSVC 2010上“可行”,但我不确定它是否合法,或者不同的布局是否会导致未定义行为。


虽然它应该在大多数编译器上正常工作,但我想问你的问题是,它比使用 bar->abar->bbar->c 更好吗? - R Sahu
@RSahu 我希望能够在循环中迭代结构体的成员,因为我需要对每个成员执行相同的操作。我可以将操作封装在一个函数中,然后使用指向这三个成员的指针调用该函数(鉴于答案似乎是“不,这并不完全安全”,这可能是我要做的),但这样有点不太方便。 - anjruu
1
@anjruu 如果你想要迭代,请使用数组。 - this
@self 我正在使用一个现有的库。所涉及的结构体表示一个点,代码的原始作者选择将一个点表示为一个带有x、y和z位置成员的结构体。 - anjruu
1
@anjruu 除非你想要未定义的行为,否则你必须调用成员。 - this
2个回答

5

这将导致未定义的行为。标准并没有完全规定结构体的布局,例如可能存在填充。


我认为你解释得很好。 - haccks
也许需要补充一下,为了提高效率并轻松满足“兼容类型”和“联合”要求,在几乎所有实现中,每个成员后面只添加最少量的填充以满足对齐约束。因此,以两个 T 开头的结构体的初始部分在实践中与两个 T 的数组兼容。 - Deduplicator
@R.. 严格的别名规则适用于基本类型,这在两种情况下都是“double”。因此,不,别名不会使此代码成为未定义行为。 - cmaster - reinstate monica
@R.. cmaster我同意没有别名问题,但是R.所述的限制适用。我甚至不会允许baz+1,因为没有数组。 - this
@this:C标准明确规定,对于任何x,只要&x是有效的,&x+1都是有效的指针算术运算。 - R.. GitHub STOP HELPING ICE
显示剩余3条评论

4
编译器可以随意地对结构体进行填充/压缩,因此严格来说,您的代码并不是100%安全的。不过,在大多数实现中它能够正常工作。

据我所知,struct 的内存布局是非常严格的,即保证使用请求的顺序。结构体内部的填充与数组中的填充相同。 - cmaster - reinstate monica
@cmaster 结构体中的填充和数组一样吗?真的吗?这在标准中有规定吗? - David Heffernan
1
@cmaster 我们正在谈论标准而不是任何具体的实现。 - David Heffernan
@cmaster - 是的,字段必须按顺序排列(除其他限制外)。这与填充/打包有什么关系? - Carl Norum
如果我知道值的对齐方式,并且了解值的顺序,我可以计算出每个结构成员的精确偏移量。是的,标准并不要求在结构和数组上下文中填充相同,但它甚至定义了_Alignof运算符,它产生类型的对齐方式。如果编译器在任何情况下使用比其更大的对齐方式,那将是非常奇怪的。这个技巧将在任何正常环境中起作用,即使没有标准的明确赞扬。 - cmaster - reinstate monica
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接