我可以在C ++中安全地将浮点数的结构转换为浮点数组吗?

时间:2017-08-26 17:51:15

标签: c++

例如我有这个结构

struct  A {
    float x;
    float y;
    float z;
};

我可以这样做吗? A a; float* array = (float*)&a; 并使用as float数组?

5 个答案:

答案 0 :(得分:27)

不,对数组进行类型转换struct将不起作用。允许编译器在成员之间添加填充

数组之间没有填充。

注意:没有什么可以阻止你进行投射,但是,在投射后使用值导致未定义的行为。

答案 1 :(得分:22)

在实际意义上,是的,你可以做到,它将适用于所有最常用的架构和编译器。

请参阅维基百科上的"Typical alignment of C structs on x86"部分。

更多详情:

  • 浮点数是4个字节,不会插入填充( 几乎所有情况)。

  • 大多数编译器也可以选择指定结构的打包,你可以强制不插入填充(即Visual Studio中的#pragma pack)

  • 保证数组在内存中是连续的。

你能保证它能在所有编译器中使用世界上所有的CPU吗?不......但我肯定希望看到一个失败的平台:)

编辑:如果有填充字节,添加static_assert(sizeof(A) == 3*sizeof(float))将使代码无法编译。所以,当你编译时,你确定它是有效的。

答案 2 :(得分:18)

这是一种严格的别名冲突,简单明了。除了第一个元素之外,对该指针的任何访问都是未定义的行为。在更复杂的情况下,无论您访问哪个元素,它都只是简单的未定义行为。

如果需要数组,请使用数组。 std::get也有using A = std::array<float, 3>; enum AElement { X, Y, Z }; int main() { A a; get<X>(a) = 3.0f; // sets X; float* array = a.data(); // perfectly well defined } 的重载,因此您可以使用它来命名每个单独的数组成员:

{{1}}

答案 3 :(得分:5)

对于g ++,您可以使用struct的属性,如下所示:

struct  A {
    float x;
    float y;
    float z;
}__attribute__((__packed__));

禁用结构对齐。

答案 4 :(得分:4)

你可以这样做,直到编译器开始优化,然后出错。

使用指向第一个元素的指针访问结构的第一个元素是未定义的行为。 &#34;未定义的行为&#34;意味着什么都可能发生。编译器可以假定没有未定义的行为。

编译器可以从中推断出许多后果:如果编译器知道你的float *指向结构的第一个元素,那么它可以推断出该数组的每个索引都等于0(因为其他任何东西都是未定义的)行为)。如果编译器不知道这一点,那么它可以推断出数组指针不能指向结构,并且改变数组元素不能改变结构元素,反之亦然。

你能看出这会怎么样吗?