将位域标记为有符号或无符号是否有意义?
标准的相关部分(ISO/IEC 9899:1999)是6.7.2.1 #4:
位域应该具有的类型是一个_Bool、signed int、unsigned int或其他实现定义类型的限定或未限定版本。
是的。这里有一个例子来自这里:
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;
只有您知道在您的项目中是否有意义;通常,对于具有多个比特的字段而言是有意义的,如果该字段可以有实际含义的负值。
将变量定义为有符号或无符号非常重要。编译器需要知道在比较和强制类型转换时如何处理变量。请查看以下代码的输出:
#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
可以的。C语言的位域本质上只是有限范围的整数。通常硬件接口会将位打包在一起,以便某些控制可以从-8到7,这种情况下需要使用有符号的位域;或者从0到15,这种情况下需要使用无符号的位域。
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;
埃里克
有符号位域(signed bitfields)有用的一个地方是在仿真中,仿真的机器比默认字长少。
我目前正在研究仿真一个48位的机器,并试图弄清楚是否可以通过位域合理地使用64位“long long”中的48位...生成的代码与如果我显式地进行所有掩码、符号扩展等操作相同,但它会更易读...
由于处理移位溢出等问题的方式不同,有符号类型的位掩码在平台硬件之间存在差异。
任何半好的 QA 工具都会警告这种用法。