【问题标题】:C++ - unions containing arraysC++ - 包含数组的联合
【发布时间】:2015-12-14 13:53:21
【问题描述】:

如果我有一个包含数组的 C++ 联合。我想使用一组唯一标识符访问数组的每个元素。 (这似乎是一件奇怪的事情。在我的应用程序中,我有一个联合,其中包含指向 8 个方向的单元格的指针,这些指针表示某个对象如何在单元格之间移动。有时编写使用数组索引的算法很方便,但是对于喜欢使用命名标识符而不是不太明显的索引的最终用户来说,这并不方便。)

例子:

union vector
{
    double x;
    double y;
    double data[2];
}

我相信xy“是一回事”,所以真的必须:

struct v
{
    double x, y;
}

union vector
{
    v data_v_format;
    double data_arr_format[2];
}

然后使用:

vector v1;
v1.data_arr_format[0] = v1.data_v_format.y; // copy y component to x

不幸的是,这给联合增加了一层难看的语法。有没有办法完成语法指定的原始任务:

union vector
{
    double x;
    double y;
    double data[2];
}

其中x 等价于data[0]y 等价于data[1]

我可以编写一个类来执行此操作,其中“逻辑命名的标识符成为函数,返回数组的单个组件” - 但有更好的方法吗?

【问题讨论】:

  • 我的 C++非常生锈了。但是,如果您尝试合并 double x, ydouble data[2] 会发生什么?
  • @EricGalluzzo 我不知道 GCC 5 会发生什么或应该发生什么......
  • 这个问题有很多与此相关的好信息:stackoverflow.com/questions/2253878/…

标签: c++ class struct unions


【解决方案1】:

无论如何,即使你能找到一种方法,从非活动联合字段读取,即不是从最后一个写入的字段读取,也是 UB。这实际上意味着常见的使用 union 在 4 个八位字节和 int 之间转换 IP 的示例是非法的。

您可以使用访问器:

struct vec
{
    double data[2];
    double& x() {return data[0];}
    double& y() {return data[1];}
};

或者,您可以查看 C++ 中的 property 实现。它将创建一个代理对象,对其的访问将被重定向到特定的数组元素。

另一种方法是使用引用,但这会增加结构的大小(+每个引用的指针大小):

struct vec
{
    double data[2];
    double& x = data[0];
    double& y = data[1];
};

【讨论】:

  • 连根拔起:在双关语中使用联合是很常见的,但这种使用实际上会产生未定义的行为。
  • @PeteBecker ,它被标准声明为 UB,但这种类型的双关语通常被保证为编译器扩展。 UB 意味着任何事情都可能发生,甚至是有保证的、明确定义和可重现的行为。也许应该提到这种依赖于编译器的扩展。
  • 注意:std::bitcast 现在提供了一种定义的方式来进行这种转换。在 C++20 之前,您可以使用 memcpy 实现相同的效果(它将被简单优化,产生相同的效果)。
【解决方案2】:

虽然在(标准)C++ 中不允许,但在 C(自 C11 起)中,您可以使用匿名结构:

// not standard C++
union vector {
    struct {
        double x;
        double y;
    };
    double arr[2];
};

一些 C++ 编译器(包括 GNU、MSVC 和 Clang)也支持匿名结构作为语言的扩展。在标准 C++ 中,您需要适应未命名的结构:

union vector {
    struct {
        double x;
        double y;
    } data;
    double arr[2];
};

这和你的例子本质上是一样的,所以你需要丑陋的语法层v.data.x等等。这更简单,因为您不需要命名内部 struct;您只需要命名作为结构实例的成员。

关于您的评论的一句话:

v1.data_arr_format[0] = v1.data_v_format.y; // copy y component to x

您评论说您将y 复制到x。请注意,在写入v1.data_arr_format 后读取v1.x 具有技术上未定义的行为。

我告诉你结构 probably 根本没有填充,因为 double 可能没有更高的对齐要求,它的大小,因此 probably 具有相同的表示作为数组。因此,在大多数实现中,这种类型的双关语可能会按预期工作,即使标准不保证这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-21
    • 2011-04-12
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多