【问题标题】:Union correct usage联合正确用法
【发布时间】:2014-12-17 06:52:05
【问题描述】:

我对联合的理解是它的所有值都分配在同一个内存地址中,并且内存空间与联合中最大的成员一样大。但我不明白我们将如何实际使用它们。 根据The C++ Programming Language,这是一个使用联合更可取的代码。

enum Type { str, num };

struct Entry {
     char* name;
     Type t;
     char* s;  // use s if t==str
     int i;    // use i if t==num
};

void f(Entry* p)
{
     if (p->t == str)
           cout << p->s;
     // ...
}

在此之后 Bjarne 说:

成员 s 和 i 永远不能同时使用,因此浪费空间。通过指定两者都应该是联合的成员,可以很容易地恢复它,如下所示: 联合价值{ 字符* s; 诠释我; }; 该语言不跟踪联合持有哪种值,因此程序员必须这样做: 结构入口{ 字符*名称; 类型 t; 价值 v; // 如果 t==str 则使用 v.s;如果 t==num 使用 v.i }; 无效 f(条目* p) { 如果 (p->t == str) cout vs. // ... }

谁能进一步解释生成的联合代码?如果我们把它变成一个联合,实际会发生什么?

【问题讨论】:

  • 网络中定义数据包时经常使用联合

标签: c++ c++11


【解决方案1】:

假设您有一台 32 位机器,具有 32 位整数和指针。您的结构可能如下所示:

[0-3] name
[4-7] type
[8-11] string
[12-15] integer

这是 16 个字节,但由于 type(您的代码中的 t)确定哪个字段有效,我们不需要同时实际存储 stringinteger 字段。所以我们可以改一下代码:

struct Entry {
  char* name;
  Type t;
  union {
    char* s;  // use s if t==str
    int i;    // use i if t==num
  } u;
};

现在的布局是:

[0-3] name
[4-7] type
[8-11] string
[8-11] integer

在 C++ 中,您最近分配的任何内容都是联合的“有效”成员,但无法知道本质上是哪个成员,因此您必须自己存储它。这种技术通常被称为“区分联合”,“鉴别器”是type 字段。

所以第二个结构需要 12 个字节而不是 16 个字节。如果您要存储大量它们,或者它们来自网络或磁盘,您可能会关心这一点。否则,这并不重要。

【讨论】:

  • 哎呀我完全不知道这个位/字节的事情。如果我不关心这个,我就不必使用工会对吗?
  • 正确。大多数 C++ 项目根本不使用联合。 C++ 中有很多你通常不需要的特性。其他示例:构面、std::ios_base::xalloc()、展示位置new 等等!
【解决方案2】:

对于下面的联合,

union mix_types {
  int l;
  struct {
    short hi;
    short lo;
    } s;
  char c[4];
} mix;

内存结构如下:-

【讨论】:

  • "内存结构就像 :-" - 你介意把它们写成文本吗?我无法阅读图像。谢谢。
  • @John 已经提供了说明,所以我只使用了图像。您可以将其与他的解释联系起来
【解决方案3】:

使用联合的另一种方法是使用不同的类型访问相同的数据。一个例子是 DirectX 矩阵结构,

typedef struct _D3DMATRIX {
    union {
        struct {
            float        _11, _12, _13, _14;
            float        _21, _22, _23, _24;
            float        _31, _32, _33, _34;
            float        _41, _42, _43, _44;

        };
        float m[4][4];
    };
} D3DMATRIX;

现在你可以做,

D3DMATRIX d;
d._11 = 20;
// Now the value of m[0][0] is 20
assert(d._11 == m[0][0]);

【讨论】:

  • 请注意,“无名”联合和结构实际上是非标准的 Microsoft Visual C++ 扩展(请参阅C4201)。从技术上讲,您必须使用 struct D3DMATRIX { union D3DMATRIX1 { struct D3DMATRIX2 { ... }; float m[4][4]; }; 才能成为标准 C++。
  • 另请注意,旧版 D3DXMath 标头使用的模式是为 C 兼容性而编写的。 C++ 不需要 typedef struct _X { ... } X; 构造。你可以做struct D3DMATRIX { ... };
猜你喜欢
  • 1970-01-01
  • 2015-10-31
  • 1970-01-01
  • 2020-06-10
  • 1970-01-01
  • 1970-01-01
  • 2018-04-07
  • 2012-08-06
  • 1970-01-01
相关资源
最近更新 更多