ANSI C是否支持有符号/无符号位域?

15

将位域标记为有符号或无符号是否有意义?

10个回答

15

标准的相关部分(ISO/IEC 9899:1999)是6.7.2.1 #4:

位域应该具有的类型是一个_Bool、signed int、unsigned int或其他实现定义类型的限定或未限定版本。


2
我认为这个问题是在询问 ANSI C(c89/c90)而不是 ISO C(c99)。 - nebuch

8

是的。这里有一个例子来自这里

struct {
  /* field 4 bits wide */
  unsigned field1 :4;
  /*
   * unnamed 3 bit field
   * unnamed fields allow for padding
   */
  unsigned        :3;
  /*
   * one-bit field
   * can only be 0 or -1 in two's complement!
   */
  signed field2   :1;
  /* align next field on a storage unit */
  unsigned        :0;
  unsigned field3 :6;
}full_of_fields;

只有您知道在您的项目中是否有意义;通常,对于具有多个比特的字段而言是有意义的,如果该字段可以有实际含义的负值。


当使用位域时,显示可能的可移植性问题(一补数与二补数)+1。 - Shmil The Cat

7

将变量定义为有符号或无符号非常重要。编译器需要知道在比较和强制类型转换时如何处理变量。请查看以下代码的输出:

#include <stdio.h>

typedef struct
{
    signed s : 1;
    unsigned u : 1;
} BitStruct;

int main(void)
{
    BitStruct x;

    x.s = 1;
    x.u = 1;

    printf("s: %d \t u: %d\r\n", x.s, x.u);
    printf("s>0: %d \t u>0: %d\r\n", x.s > 0, x.u > 0);

    return 0;
}

输出:

s: -1    u: 1
s>0: 0   u>0: 1

编译器使用单个位(1或0)存储变量。对于有符号变量,最高位决定符号(高位被视为负数)。因此,有符号变量在二进制中存储为1,但被解释为负一。
扩展这个话题,一个无符号的两位数的范围是0到3,而一个有符号的两位数的范围是-2到1。

2
我认为Andrew并不是在谈论单个比特位字段。例如,4位字段:3位数字信息,1位符号位。这完全有意义,尽管我承认我无法立即想出这样的场景。
更新:我并不是说我不能想到多比特位字段的用途(在2400bps调制解调器时代,我一直使用它们来尽可能压缩数据以进行传输),但我无法想到有符号比特位字段的用途,特别是没有一个古雅明显的用途,会让读者有“啊哈”时刻。

有一些情况下这是有用的。在计算几何中,您经常需要存储诸如“下一个,上一个,无,相同”的信息。这正好需要两位。如果您可以将结构压缩到像2^n这样的良好大小,那么您可能会获得一个很好的性能提升。 - Nils Pipenbrinck

2

可以的。C语言的位域本质上只是有限范围的整数。通常硬件接口会将位打包在一起,以便某些控制可以从-8到7,这种情况下需要使用有符号的位域;或者从0到15,这种情况下需要使用无符号的位域。


2

ANSI-C提供有符号和无符号位域,这是必需的。这也是为IEEE-754浮点类型[[1][5][10]],[[1][8][23]]和[[1][10][53]]编写调试器叠加层的一部分。在对这些数据进行机器类型或网络转换时非常有用,或者在发送到链接(例如视频卡纹理)之前检查将双精度(64位用于数学)转换为半精度(16位用于压缩)。

// Fields need to be reordered based on machine/compiler endian orientation

typedef union _DebugFloat {
   float f;
   unsigned long u;
   struct _Fields {
        signed   s :  1;
        unsigned e :  8;
        unsigned m : 23;
      } fields; 
   } DebugFloat;

埃里克


1

有符号位域(signed bitfields)有用的一个地方是在仿真中,仿真的机器比默认字长少。

我目前正在研究仿真一个48位的机器,并试图弄清楚是否可以通过位域合理地使用64位“long long”中的48位...生成的代码与如果我显式地进行所有掩码、符号扩展等操作相同,但它会更易读...



0

由于处理移位溢出等问题的方式不同,有符号类型的位掩码在平台硬件之间存在差异。

任何半好的 QA 工具都会警告这种用法。


-4
如果一个“位”是有符号的,则其范围为-1、0、1,然后成为三进制数字。我认为这里不适合使用标准缩写,但可以引发有趣的讨论 :)

错误。你得到-1、-0、+0、+1。两位二进制,四种状态。 - Thorsten79
1
嗯,我认为C标准在整数运算中并不包括负零的概念。 - tzot
3
实际上,从一个比特中你只能得到两种状态(如果你理解二进制补码算术,这并不奇怪)。它们是0和-1。 - Nils Pipenbrinck
哦,重新阅读这篇文章让我觉得这可能是一个我们都错过的玩笑...三进制数字是“tit”... - freespace
啊,终于有人看到这个笑话了... 或许下次我应该再明显一点 :P - workmad3
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接