联合存储在内存中

Storage of Union In Memory

本文关键字:内存 存储      更新时间:2023-10-16

我读到在Union中,数据成员占用相同的内存块。所以,我试着用这个实现读取英文字母表的ASCII代码。

union {
    int i;
    char a,b;
}eps;
eps.i=65;
cout<<eps.a<<eps.b;

我得到了65的正确输出(A),但ab似乎在内存中占据了相同的位置。

Q。但是,一个2字节的整数,a不应该占据前8位,b不应该占据其他8位吗?

此外,当在并集内使用多个整数重复上述操作时,它们似乎具有相同的值。

Q。那么,这是否意味着给定数据类型的每个变量的行为都像对同一数据类型的任何其他变量的引用一样?(给定变量int i,j,k,l.....的简单加法)

Q。既然所有其他变量都指向同一位置,我们能在并集中只使用给定数据类型的一个(不同的)变量吗?

编辑

我想提到的是,当在并集中添加更多变量时,这只是意味着像int i,j,k...一样添加它们,而不是使用将它们包装在struct中或以任何其他方式。

正如Baum mit在聊天(和评论)中澄清的那样,以下是供其他/未来用户查看的讨论。

读取不是上次写入的union的成员是未定义的行为。这意味着你的代码可以做任何事情,争论它的行为是没有意义的。

若要在类型之间执行转换,请使用适当的强制转换,而不是联合。

编辑后回答您的问题:

Q。但是,一个2字节的整数,a不应该占据前8位,b不应该占据其他8位吗?

正如你所说,工会的每个成员都有相同的空间。由于ab是不同的成员,它们也共享相同的空间(从某种意义上说,它们都住在属于联盟的空间中的某个地方)。联盟的实际布局可能是这样的:

byte 0 | byte 1 | byte 2 | byte 3
i        i        i        i
a
b

Q。那么,这是否意味着给定数据类型的每个变量都充当同一数据类型的任何其他变量的引用?

不,同一时间的成员不会相互参照。如果您有对对象的引用,则可以通过引用可靠地访问该对象。同一类型的两个成员可能会使用完全相同的内存,但您不能依赖这一点。我上面所说的规则仍然适用。

Q。既然所有其他变量都指向同一位置,我们能在并集中只使用给定数据类型的一个(不同的)变量吗?

您可以拥有任意多个相同类型的成员。他们可能生活在完全相同的记忆中,也可能不生活在完全一样的记忆中。这并不重要,因为无论如何你只能访问最后一个写入的。

您误解了工会的作用。它们不能保证以任何可预测的方式共享内存。它们只是提供了一种方式来表示一个实体可以存储几种类型的信息中的一种。如果您设置了一种类型,那么其他类型都是未定义的(可以是任何类型,甚至是与您输入的数据无关的类型)。它们如何共享内存取决于编译器,可能取决于启用的优化(例如内存对齐规则)。

话虽如此,在大多数情况下(禁用优化),您会发现并集的每个部分都从并集的字节0开始(不依赖于此)。在代码中,union{int i;char a,b;}表示"此并集可以是整数i、字符a或字符b"。您可以使用(正如许多人所建议的)union{int i;struct{char a,b;}},它会告诉编译器:"这个并集可以是整数i,也可以是字符a和b的结构"。

因此,从一种类型转换为另一种类型或转换为其组件字节不是联合的工作。相反,您应该使用强制转换。

那么你会在哪里使用工会呢?这里有一个例子:

struct {
    int type; // maybe 0 = int, 1 = long, ...
    union {
        char c;
        int i;
        long l;
        float f;
        double d;
        struct {
            int x;
            int y;
        } pos;
        // etc.
    } value;
};

有了这样的对象,我们可以动态存储任何类型的数字(或者我们可能想要的任何其他数字,比如本例中的2D位置),同时使用外部变量跟踪实际存在的数字。与没有并集的等效代码相比,它使用的内存要少得多,并且使设置/获取安全(我们不需要到处投射指针)

回想一下,union类型是一组可供选择的可能性。正式的措辞是,它是其字段所属所有类型的共同产品

union {
  int i;
  char a,b;
}

在语法上等同于:

union {
  int i;
  char a;
  char b;
}

ab属于同一类型,它们在一起的贡献并不比单独取下的贡献多。换句话说,b是多余的。

您需要将ab字段封装在struct中,以便将它们捆绑为union的一个替代方案。

union {
  int i;
  struct {
    char a;
    char b;
  };
}

此外,在大多数平台上,int类型是32位宽的积分类型,char是8位宽的整数类型——我通常这么说,因为尺寸的正式定义不仅仅是int大于或等于char

因此,假设我们有charint的常见定义,第二种选择是16位宽,编译器有机会将其放置在较大字段(32位)占用的相同空间内。

另一个问题是字节排序,不同平台的字节排序可能不同。

您也许可以通过在结构中填充缺失的字节以达到32位来使其工作(在实践中,它几乎总是工作的):

union {
  int i;
  struct {
    char a;
    char b;
    char c;
    char d;
  };
}

(例如,考虑IPv4地址的int表示,以及用于解决字节排序问题的htons函数)。

然而,最终的规则是由C语言规范规定的,这些规范没有指定这一点。

为了安全起见,我会选择一组函数来逐位屏蔽字节,而不是使用union,但如果你针对的是特定的平台,并且上述联合有效。。。