boo*_*leg 12 c gcc bit-shift clang bit-fields
让我们考虑以下计划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位的位字段在移位时会被签名?我想,因为这是既相一致,这是不是一个错误gcc和clang.我一定错过了一些关于比特字段(或移位)如何工作的信息但是什么?如何转换无符号值会产生有符号值?
整数推广应用于草案C99标准部分所涵盖的转换操作数,6.5.7 按位移位操作符第3段说明(强调我的前进):
对每个操作数执行整数提升.[...]
并且第2段中的6.3.1.1 布尔,字符和整数部分涵盖了位字段的整数提升,其中说:
如果可以使用int或unsigned int,则可以在表达式中使用以下内容:
并包含以下项目符号:
- _Bool,int,signed int或unsigned int类型的位字段.
然后说:
如果int可以表示原始类型的所有值,则该值将转换为int; 否则,它将转换为unsigned int.这些被称为整数促销.48)所有其他类型的整数提升不变.
如果int可以表示原始类型的所有值(由宽度限制,对于位字段),则该值将转换为int; 否则,它将转换为unsigned int.这些被称为整数促销.58)所有其他类型由整数促销保持不变.
所以这是预期的行为.
| 归档时间: | 
 | 
| 查看次数: | 1138 次 | 
| 最近记录: |