c - 带符号的位字段表示

标签 c bit-fields

我制作了一个字段大小为 1 位的位字段,并使用 int 而不是 unsigned。后来当我试图检查字段的值时,我发现该值为 -1。 我使用这段代码来检查二进制表示和我的位字段的值:

#include <stdio.h>
#include <stdlib.h>

union {
    struct {
        int bit:1;
    } field;
    int rep;
} n;

int main() {

int c, k;
n.field.bit=1;
 for (c = 31; c >= 0; c--)
  {
    k = n.rep >> c;

    if (k & 1)
      printf("1");
    else
      printf("0");
  }

  printf("\n %d \n", n.field.bit);

return 0;
}

输出是: 00000000000000000000000000000001

-1

在那种情况下,为什么我的位字段的值是 -1 并且当我使用 signed int 而不是 unsigned 时它总是负数?

最佳答案

如果您期望值的某些内容除了它可以容纳 n 位之外,您不应该使用普通的 int 作为位域类型- 根据 C11 标准,位域中的 int 是有符号还是无符号实际上是实现定义的 6.7.2p5 :

5 Each of the comma-separated multisets designates the same type, except that for bit-fields, it is implementation-defined whether the specifier int designates the same type as signed int or the same type as unsigned int.

在您的情况下,int 指定与 signed int 相同的类型;这是 the default in GCC :

Whether a “plain” int bit-field is treated as a signed int bit-field or as an unsigned int bit-field (C90 6.5.2, C90 6.5.2.1, C99 and C11 6.7.2, C99 and C11 6.7.2.1).

By default it is treated as signed int but this may be changed by the -funsigned-bitfields option.

因此,任何理智的程序总是指定 signed intunsigned int,具体取决于哪个适合当前用例。


然后由实现定义带符号的数字是一个补码还是二进制补码 - 或者可能是符号和大小 - 如果它们是一个补码或 s-and-m,那么唯一可以存储的值1位是符号位,因此为0;所以一个位的带符号位域可能只对 2 的补码有意义。

您的系统似乎使用 2 的补码 - 例如what GCC always uses :

Whether signed integer types are represented using sign and magnitude, two’s complement, or one’s complement, and whether the extraordinary value is a trap representation or an ordinary value (C99 and C11 6.2.6.2).

GCC supports only two’s complement integer types, and all bit patterns are ordinary values.

因此位值 10 被解释为带符号的二进制补码数:前者设置了符号位,因此它是负的( -1) 而后者没有设置符号位,因此它是非负数 (0)。

因此对于 2 位的带符号位域,可能的位模式及其在 2 的补码机上的整数值是

  • 00 - int 值为 0
  • 01 - int 值为 1
  • 10 - 具有 int 值 -2
  • 11 - int 值为 -1

在一个 n 位字段中,最小的有符号数是 - 2^(n - 1),最大的是 2^(n-1) - 1。

现在,当对秩小于 int 的有符号整数操作数执行算术运算时,它首先被转换为 int,因此值 -1 符号扩展为全角int默认参数提升也是如此;该值在传递给 printf 时被符号扩展为(全角)int

因此,如果您希望从一个位域中获得一个合理的值,请使用 unsigned bit: 1; 或者如果要将其理解为 bool 标志,则使用 _Bool bit: 1;

关于c - 带符号的位字段表示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42527387/

相关文章:

c++ - 使用模运算的正确方法

c - 从 struct bitfield 以十六进制打印完整的 uint32_t

c - 用于在 c 中以十六进制格式打印结构中的位字段的格式说明符

c - 使用 malloc 和 free 理解指针

C scanf格式化

c - 如果两个结构具有本质上相同的结构,则取消一个结构定义

c - 函数声明中的参数名称(不带类型)(循环引用)

C++位域成员变量初始化值(UE4示例)

c - 如何计算包含一些未命名成员和零大小位域的位域结构的大小?

c - 警告只有一个位域,而不是两个?