【问题标题】:Naming Array Elements, or Struct And Array Within a Union命名数组元素或联合中的结构和数组
【发布时间】:2012-08-16 01:12:30
【问题描述】:

考虑以下结构:

struct Vector4D
{
   union
   {
      double components[4];
      struct { double x, y, z, t; } Endpoint;
   };
};

在我看来,我在 WinApi 的 IPAddress 结构中看到了类似的东西。这个想法是让我可以按索引和名称使用数组组件,例如:

Vector4D v;
v.components[2] = 3.0;
ASSERT(v.Endpoint.z == 3.0) //let's ignore precision issues for now

在 C++ 标准中,保证在 POD 结构的开头不会有“空”空间,也就是说,元素 x 将位于 Endpoint 结构的开头。目前很好。但我似乎没有找到任何保证不会有空格或填充,如果你愿意的话,在xy,或yz 等之间。我还没有签出不过是 C99 标准。

问题是,如果 Endpoint struct 元素之间有空格,那么这个想法就行不通了。

问题:

  1. 我说得对吗,确实不能保证这在 C 或 C++ 中都能工作。

  2. 这实际上适用于任何已知的实现吗?换句话说,您知道有哪些实现方式不起作用吗?

  3. 是否有任何标准(我的意思不是特定于编译器)的方式来表达相同的想法?也许 C++0x 对齐功能可能会有所帮助?

顺便说一句,这不是我在生产代码中做的事情,别担心,只是好奇。提前致谢。

【问题讨论】:

标签: c++ c c++11 unions memory-alignment


【解决方案1】:
  1. 是的
  2. 取决于架构的对齐需求和编译器策略
  3. 不,但你可以创建一个对象包装器(但你最终会得到.z() 而不仅仅是.z

大多数编译器应该支持使用编译指示或属性压缩结构。以#pragma pack 为例。

【讨论】:

    【解决方案2】:

    您可以通过引用数组的每个元素来规避任何内存对齐问题,只要您在类中的引用之前声明数组以确保它们指向有效数据。话虽如此,我怀疑对齐是否会成为双打的问题,但可能适用于其他类型(也许浮动在 64 位拱门上?)

    #include <iostream>
    using namespace std;
    
    struct Vector4D
    {
        Vector4D() : components(), x(components[0]), y(components[1]), z(components[2]), t(components[3]) { }
    
        double components[4];
    
        double& x;
        double& y;
        double& z;
        double& t;
    };
    
    int main()
    {
        Vector4D v;
    
        v.components[0] = 3.0;
        v.components[1] = 1.0;
        v.components[2] = 4.0;
        v.components[3] = 15.0;
    
        cout << v.x << endl;
        cout << v.y << endl;
        cout << v.z << endl;
        cout << v.t << endl;
    }
    

    希望这会有所帮助。

    【讨论】:

    • 我也想过这个,但它有一个主要缺点。当我采用 const Vector4D 时,组件将是 const,但我将能够通过引用更改它们。这是非常非常糟糕的
    • 您始终可以使用传播 const-ness 的更智能的代理来解决这个 C++ 问题。
    • @Matt,这让我想知道在使用特殊声明说明符时传播常量的引用类型。比如,对于常量vv.x 的类型为double const。这样的语言功能有意义吗?
    • @Johannes:恐怕这只会使语言进一步膨胀。就我个人而言,默认情况下我更倾向于 constness 传播,但这是 constness 的“功能”视图,而 C++ 与“技术”方面根深蒂固。
    • 现在向量结构是原来的两倍。
    【解决方案3】:

    说到标准,有两个问题:

    • 未指定在向联合中的元素写入并从另一个元素中读取时会发生什么,请参阅 C 标准 6.2.6.1 和 K.1
    • 标准不保证结构体的布局与数组的布局相匹配,详见C标准6.7.2.1.10。

    话虽如此,实际上这将适用于普通编译器。事实上,这种代码被广泛传播,并且经常用于将一种类型的值重新解释为另一种类型的值。

    【讨论】:

    • 您指的是哪个 C 标准? C90 还是 C99?
    • 我指的是C99标准。
    【解决方案4】:

    填充字节不会引起问题,因为所有变量都是double 类型。编译器会将Vector4D 视为double 数组。这意味着,v.Endpoint.z 本质上与v[2] 相同。

    【讨论】:

    • 你的意思是实际上还是你的意思是标准要求我的代码正常工作?
    • 你确定吗?我认为double 有 6 个字节没有问题。
    • @Let_Me_Be 6 字节 doubles 与 2 字节填充之间如何破坏此代码?
    • @Vijay 任何填充都会破坏代码。数组没有填充。
    • @Let_Me_Be Vector4D 本质上是doubles 的数组。 v.Endpoint.z 将被编译为v + 2
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 2020-02-01
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    • 2013-01-01
    相关资源
    最近更新 更多