Mof*_*ofX 8 c gcc compiler-warnings suppress-warnings
有没有办法在这段代码中抑制gcc生成的警告:
int main() {
struct flagstruct {
unsigned flag : 1;
} a,b,c;
a.flag = b.flag | c.flag;
return a.flag;
}
Run Code Online (Sandbox Code Playgroud)
警告是
warning: conversion to 'unsigned char:1' from 'int' may alter its value [-Wconversion]
Run Code Online (Sandbox Code Playgroud)
看起来两个标志在组合在一起时扩展为int.我认为真的很奇怪的是,将两个标志中的任何一个投射到无符号都会发出警告.
a.flag = (unsigned)b.flag | c.flag;
Run Code Online (Sandbox Code Playgroud)
这是一个编译器错误还是它应该以这种方式工作?
看起来两个标志在组合在一起时扩展为int.
这是整数提升,它在C99标准的奇怪措辞条款6.3.1.1:2中定义:
如果可以使用int或unsigned int,则可以在表达式中使用以下内容:
...
- _Bool,int,signed int或unsigned int类型的位字段.如果int可以表示原始类型的所有值,则该值将转换为int; 否则,它将转换为unsigned int.这些被称为整数促销.整数促销不会更改所有其他类型.
首先,处理器不直接对位字段计算,也可以不具有指令来计算上更窄的整数类型char和short.C标准通过仅具有上定义的算术运算捕获此int,unsigned int和更宽的整数类型.在上面标准上写着"可以使用"的情况下,它正在尝试(很差)表示所有短类型和位字段必须在参与算术时int或unsigned int之前被提升.
其次,所有无符号位字段是不够宽,包括为无法表示的值int被提升至int.换句话说,GCC通过将您的无符号位字段提升为已签名的行为来表现int,并且像您一样添加显式强制转换似乎是未来(以及针对警告)的最佳策略.
我认为真的很奇怪的是,将两个标志中的任何一个投射到无符号都会发出警告.
通常的算术转换是C标准中另一个有趣的概念(C99中的6.3.1.8),结果是如果两个操作数中的任何一个被显式转换为a unsigned int,那么另一个操作数也会隐式地转换为unsigned int和|操作是unsigned int产生unsigned int结果的操作.
换句话说,(unsigned)b.flag | c.flag严格相当于(unsigned)b.flag | (unsigned)c.flag.在这种情况下,编译器认为没有理由警告分配,因为计算的结果是a unsigned int.
一年后我修改了这个问题:
刚刚用不同的编译器版本再次测试。当我第一次遇到这个错误时(现在我很确定,我可以称它为错误),我已经意识到该警告仅存在于 clang < 3.1 和当时的所有 GCC 版本中。所有低于 5 的 GCC 版本仍然会产生该警告。
由于没有其他方法来消除错误,唯一的解决方案是更新到 GCC > 5 或添加 unsigned cast a.flag = (unsigned)b.flag | c.flag;。