【问题标题】:value of members of unions with bit-fields具有位域的联合成员的值
【发布时间】:2019-05-06 01:30:24
【问题描述】:

我正在尝试了解如何为包含位域的联合分配内存。

我查看了与此类似的帖子和问题,并且了解到大多数情况下都涉及填充,具体取决于在结构中声明成员的顺序。

1.

union Example
{ int i:2;
  int j:9; 
};


int main(void)
{ 
   union Example ex;
   ex.j=15;
   printf("%d",ex.i);
}

输出:-1

2.

union Example
{ unsigned int i:2;
  int j:9; 
};


int main(void)
{ 
   union Example ex;
   ex.j=15;
   printf("%d",ex.i);
}

输出:3

有人可以解释一下输出吗?它只是这种情况的标准输出吗? 我在 ubuntu 中使用内置的 gcc 编译器

【问题讨论】:

  • 先从union Example { unsigned u; int i:2; int j:9; };union Example ex = {0};开始初始化所有,然后试试你的测试。
  • 没有标准输出,由编译器决定
  • 这听起来可能有点愤世嫉俗,但它是基于跨多个编译器环境的这种机制的经验的有用建议。 “我正在尝试了解如何为包含位域的联合分配内存。”,但我建议不要这样做。编译器被允许并且确实以不同的方式处理这个问题,如果你了解编译器是如何做到的,你就会开始做出错误的假设。
  • 我见过的所有使用位域的情况都是使用结构而不是联合。你确定你应该在这种情况下查看工会吗?
  • 是的,是工会

标签: c structure unions bit-fields


【解决方案1】:

编译器为联合中的位域分配位的方式恰好与j 的低位与i 的位重叠。因此,当j 设置为 15 时,i 的两位分别设置为 1。

i 是一个用int i:2 声明的两位有符号整数时,您的编译器会将其解释为两位二进制补码数。通过这种解释,第 11 位表示 -1。

i 是一个两位无符号整数,用unsigned int i:2 声明时,它是纯二进制,没有符号位。按照这种解释,11 位代表 3。

下面的程序显示,将有符号两位整数设置为 -1 或将无符号两位整数设置为 3 在联合中产生相同的位模式,至少在您的 C 实现中是这样。

#include <stdio.h>


int main(void)
{
    union Example
    {
        unsigned u;
        int i : 2;
        int j : 9;
        unsigned int k : 2;
    } ex;

    ex.u = 0;
    ex.i = -1;
    printf("ex.i = -1:  %#x.\n", ex.u);

    ex.u = 0;
    ex.j = 15;
    printf("ex.j = 15:  %#x.\n", ex.u);

    ex.u = 0;
    ex.k = 3;
    printf("ex.k =  3:  %#x.\n", ex.u);
}

输出:

ex.i = -1:0x3。 ex.j = 15:0xf。 例如k = 3:0x3。

请注意,编译器还可以从高位到低位而不是从低位到高位分配位,在这种情况下,j 的高位将与i 重叠,而不是低位。此外,编译器可以为 9 位 j 使用不同大小的存储单元,而不是为 2 位 i 使用不同大小的存储单元,在这种情况下,它们的位可能根本不会重叠。 (例如,它可能对i 使用单个八位字节,但对j 使用一个 32 位字。八位字节将与 32 位字的某些部分重叠,但不一定是该部分用于j。)

【讨论】:

    【解决方案2】:

    示例 1

    #include <stdio.h>
    
    union Example
    { int i:2;
      int j:9; 
    };
    
    
    int main(void)
    { 
       union Example ex;
       ex.j=15;
       printf("%d",ex.i);
       printf("\nSize of Union : %lu\n" , sizeof(ex));
    
       return 0;
    }
    
    

    输出:

    -1
    Size of Union : 4
    

    观察:

    从这个输出中,我们可以推断即使我们使用 9 位(最大值),编译器也会分配 4 个字节(因为填充)。 语句 union Example ex; 为 Union Example 对象 ex 分配 4 个字节的内存。 语句ex.j=15; 将 0x0000000F 分配给该 4 字节内存。所以对于 j 它为 9 位分配 0-0-0-0-0-1-1-1-1。 声明 printf("%d",ex.i); 尝试打印 ex.i(这是 2 位)。我们有上一个语句的 1-1。

    有趣的部分来了,ex.i 是signed int 类型。因此第一位用于分配有符号表示,并且大多数 cpu 以 2 的补码形式进行有符号表示。 因此,如果我们反转 1-1 的 2 的补码,我们将得到值 1。所以我们得到的输出是 -1。

    示例2

    #include <stdio.h>
    
    union Example
    { unsigned int i:2;
      int j:9; 
    };
    
    
    int main(void)
    { 
       union Example ex;
       ex.j=15;
       printf("%d",ex.i);
    
    
       return 0;
    }
    
    

    输出:

    3
    

    观察:

    语句 union Example ex; 为 Union Example 对象 ex 分配 4 个字节的内存。 语句 ex.j=15; 将 0x0000000F 分配给该 4 字节内存。所以对于 j 它为 9 位分配 0-0-0-0-0-1-1-1-1。 声明 printf("%d",ex.i); 尝试打印 ex.i(这是 2 位)。我们有上一个语句的 1-1。

    和上面的例子一样,但是这里的 ex.i 是 unsigned int 类型。因此这里没有使用符号位来表示。 因此,存储在 2 位位置的任何内容都是精确值。因此输出为 3。

    希望我消除了您的疑虑。请在互联网上检查 2 和 1 的补码。

    【讨论】:

      猜你喜欢
      • 2012-05-28
      • 2023-03-31
      • 2014-01-12
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2015-01-24
      • 2019-10-21
      • 2018-08-14
      相关资源
      最近更新 更多