【问题标题】:Comparison between structs in C using bitfields使用位域比较 C 中的结构
【发布时间】:2018-01-17 17:31:51
【问题描述】:

所以我真的无法理解这两个代码段之间的区别。我对位域的了解是,我在内存中保留了多少位用于这个 int。但是为什么负数出现在 2nd Struct 中呢?

#include<stdio.h>
#include<string.h>
typedef struct {
        unsigned int i:1;
        unsigned int k:31;
        int x;
}Struc1;
typedef struct{
        int i:1;
        int k:4;
        int x;
}Struc2;
int main()
{
        Struc1 s1={1,13,13};
        printf("%d %d %d\n",s1.i,s1.k,s1.x);
        Struc2 s2={1,13,13};
        printf("%d %d %d\n",s2.i,s2.k,s2.x);
        return 0;
}

输出:

1 13 13
-1 -3 13

【问题讨论】:

  • 你知道负数在 C 中是如何表示的吗?提示:最左边的位是符号。
  • 几乎所有关于位域的内容都是实现定义的。当您将13 存储到一个 4 位位字段中时,您可能会存储一个有符号或无符号值。 13 具有位模式1101;高位被设置;如果您的普通 int 位域是有符号类型,它将被视为负数。如果您希望它未签名,请这样说:unsigned k:4;int 在此上下文中是可选的)。
  • C11 §6.7.2.1 footnote 125 如上面 6.7.2 所述,如果实际使用的类型说明符是 int 或定义为 int 的 typedef-name,那么它是否是实现定义的 bit-字段是有符号或无符号的。并且C11 §6.7.2 ¶5 每个逗号分隔的多重集都指定相同的类型,除了位域,说明符int 指定与signed int 相同的类型还是与@ 相同的类型是实现定义的987654335@.
  • 这些注释意味着您无法分辨int x:1; 位域中存储的值。它可以存储零或非零;除了阅读编译器文档或实验之外,您无法判断非零值是 -1 还是 +1。它没有可移植的解释,但这不是主要问题,因为位域通常没有可移植的解释。
  • @ZeyadIbrahim: 通常情况下,int 的含义与signed int 相同;位域是我能想到的唯一地方,它有时与unsigned int 相同——这取决于你的编译器。因此,默认情况下,大多数人会期望结构的 int 成员是有符号数量。

标签: c memory struct bit-fields


【解决方案1】:

这是 C 中intsigned int 可能不同的地方。

有位域,没有signedunsignedint 可以被视为signed intunsigned int。根据 OP 报告的输出,int 的这种实现定义的行为似乎类似于 signed int

typedef struct{
  int i:1;  // like signed int i:1; for OP
  int k:4;  // like signed int k:4; for OP
  int x;
}Struc2;

i 位域的范围可能是[-1...0],而k 的范围可能是[-8...7]。通过Struc2 s2={1,13,13}; 用超出其范围的值初始化一个有符号整数定义的实现(详情:C11dr 6.3.1.3 3)。

一个常见的实现定义行为是环绕。比如Struc2 s2 = {1-2, 13-16, 13};Struc2 s2 = {-1, -3, 13};


使用位域时,建议尽可能使用unsigned。如果需要int 位域,请使用signed int

【讨论】:

    【解决方案2】:

    结构位字段表示为结构的数据成员保留的内存。在处理bit-field 时,如果输入是signed 类型,则应注意sign bit

    struc2 的内存分配

    typedef struct{
            int i:1;
            int k:4;
            int x;
    }Struc2;
    

    1)会员i只保留one bits

     -------
    |  1    |
     -------
            i
            |
            this is only first and last bit
    

    int i : 1 ; 如果没有为 variable/constant 提及类型,则默认编译器将考虑为 signed 类型并且如果 sign(MSB) 有符号整数位是1 表示它将是 否。 2's complement1-1。所以s2.i = -1

    注意:在C语言中,否定的no以补码的形式存储在内存中

    2)对于成员k4 bits 是保留的(因为您正在存储13),如下所示

           ---------------------------
    13 => | 1   |    1   |  0   |  1  |
           ---------------------------
           0x103  0x102   0x101  0x100                      
            |
          sign bit
    

    在这种情况下sign bit 也是1 所以s2.k 将是 和多少?取补码(一个补码 + 1)。

            13 => 1101
               => 0010 (one's complement)
                    +1
                  -----
                  0011 => 3  since sign bit was 1 so s2.k = -3
                  -----    
    

    【讨论】:

      【解决方案3】:

      您的系统是小端序,因此第一位是最右边的有符号位,这就是为什么在您的第二个 struct 中插入奇数,因此它将第一位作为有符号位并给出负值。

       typedef struct{   
          int i:1;   //Here you inserting **1** so it will take as signed bit. 
          int k:4;   //Here you inserting odd value **13** so it will take negative
          int x;     //This is also signed but it is **32** bit so it has enough space to store your **13** integer value.
        }Struc2;
      

      如果您不想要负值,请将其作为 unsigned 或增加位数分配。干杯..

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-09
        • 1970-01-01
        • 2015-09-08
        • 1970-01-01
        • 2020-09-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多