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

Posted

技术标签:

【中文标题】ANSI C 是不是支持有符号/无符号位域?【英文标题】:Does ANSI C support signed / unsigned bit fields?ANSI C 是否支持有符号/无符号位域? 【发布时间】:2010-09-14 01:45:40 【问题描述】:

将位字段限定为有符号/无符号是否有意义?

【问题讨论】:

【参考方案1】:

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

位域的类型应为合格或不合格 _Bool、signed int、unsigned int 或其他一些实现定义的版本 输入。

【讨论】:

我认为问题是关于 ANSI C (c89/c90) 而不是 ISO C (c99)。【参考方案2】:

是的。来自here的例子:

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 表示使用位域时可能存在的可移植性问题(一对二补码)【参考方案3】:

将变量限定为有符号或无符号非常重要。编译器需要知道如何在比较和强制转换期间处理变量。检查此代码的输出:

#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。

【讨论】:

【参考方案4】:

是的,可以。 C 位域本质上只是有限范围的整数。硬件接口经常将位打包在一起,使得某些控制可以从 -8 到 7,在这种情况下您确实需要一个有符号位字段,或者从 0 到 15,在这种情况下您需要一个无符号位-字段。

【讨论】:

【参考方案5】:

我认为 Andrew 不是在谈论单比特位域。例如,4 位字段:3 位数字信息,1 位符号。这完全有道理,尽管我承认我无法想出这样的场景。

更新:我并不是说我想不出多位位域的用途(早在 2400bps 调制解调器时代就一直使用它们来尽可能地压缩数据以进行传输),但我可以不要想到有符号位字段的用途,尤其是对于读者来说不是一个古怪、明显的“啊哈”时刻。

【讨论】:

有些场景是有用的。在计算几何中,您通常必须存储诸如“下一个、上一个、无、相同”之类的信息。这恰好是两个位。碰巧你可以将你的结构压缩到一个不错的大小,比如 2^n,你可能会得到一个很好的性能提升。【参考方案6】:

当然,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;

埃里克

【讨论】:

【参考方案7】:

有符号位域很有用的一个地方是在仿真中,其中仿真机器的位数少于您的默认字。

我目前正在研究模拟 48 位机器,并正在尝试通过位域从 64 位“long long”中使用 48 位是否合理......生成的代码将是相同的好像我做了所有的屏蔽、符号扩展等,但它会读起来更好......

【讨论】:

【参考方案8】:

根据这个参考,有可能:http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=/com.ibm.vacpp6m.doc/language/ref/clrc03defbitf.htm

【讨论】:

【参考方案9】:

位掩码签名类型因平台硬件而异,这取决于它如何处理移位等溢出。

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

【讨论】:

【参考方案10】:

如果一个“位”被签名,那么你的范围是-1、0、1,然后变成一个三进制数字。我认为标准的缩写在这里不合适,但可以进行有趣的对话:)

【讨论】:

错了。你得到-1、-0、+0、+1。两位,四种状态。 可能像 -2, -1, 0, 1 这样更有意义,你几乎不需要 -0 嗯。我不认为 C 标准在整数算术中包含负零的概念。 实际上,从一个位开始,您只能得到两种状态(如果您了解二进制补码算术,那就不足为奇了)它们是 0 和 -1。 @Nils:是的,从一个位你只能得到两个状态,而从两个位你可以得到四个状态。如果您的评论是对 workmad3 的回复,也许您应该在评论前加上“@workmad3”。

以上是关于ANSI C 是不是支持有符号/无符号位域?的主要内容,如果未能解决你的问题,请参考以下文章

C语言中,64位无符号整型如何进行开方运算?

C语言中,64位无符号整型如何进行开方运算?

Java不提供无符号整数类型?谢谢

为啥在有符号和无符号表示之间转换一个数字?

为啥 SQL Server 不支持无符号数据类型?

c中无符号(unsigned)和有符号(signed)两种类型。