[英]Unsigned integer bit field shift yields signed integer
让我们考虑以下程序test.c
:
#include <stdio.h>
struct test {
unsigned int a:5;
};
int main () {
unsigned int i;
struct test t = {1};
for (i = 0; i < t.a << 1; i++)
printf("%u\n", i);
return 0;
}
使用gcc -Wsign-compare test.c
编译时,会生成以下警告(使用gcc 4.8.1进行测试):
test.c:9:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
for (i = 0; i < t.a << 1; i++)
^
clang -Wsign-compare test.c
生成以下内容(使用clang 3.2进行测试):
test.c:9:19: warning: comparison of integers of different signs: 'unsigned int' and 'int' [-Wsign-compare]
for (i = 0; i < t.a << 1; i++)
~ ^ ~~~~~~~~
1 warning generated.
因此,右操作数(移位的无符号位字段)变为有符号的int。 此警告显示包含的1到31之间的任何位字段值。 对于更高的值,不会产生警告。 这很奇怪。
这是使用unsigned short
, unsigned int
和unsigned long
类型的位字段测试的。 后者不会显示包含32到64之间的位字段值的任何警告。
当没有进行移位时没有警告,因此位字段按预期无符号。
为什么大小低于32位的位字段在移位时会被签名? 我认为这不是一个bug,因为这与gcc
和clang
都是一致的。 我一定错过了一些关于比特字段(或移位)如何工作的信息但是什么? 如何转换无符号值会产生有符号值?
整数推广应用于草案C99标准第6.5.7
节中所涵盖的转换操作数。 按位移位操作符第3段说( 强调我的前进 ):
对每个操作数执行整数提升。[...]
第6.3.1.1
节布尔,字符和整数第2节中介绍了位域的整数提升,其中说明:
如果可以使用int或unsigned int,则可以在表达式中使用以下内容:
并包含以下项目符号:
- _Bool,int,signed int或unsigned int类型的位字段 。
然后说:
如果int可以表示原始类型的所有值,则该值将转换为int; 否则,它将转换为unsigned int。 这些被称为整数促销 。 48)所有其他类型的整数提升不变。
如果int可以表示原始类型的所有值(由宽度限制,对于位字段) ,则该值将转换为int; 否则,它将转换为unsigned int。 这些被称为整数促销。 58)所有其他类型由整数促销保持不变。
所以这是预期的行为。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.