我正在尝试了解c ++应用程序中整数提升和比较的工作方式。
#include <cstdint>
int main(void)
{
uint32_t foo = 20;
uint8_t a = 2;
uint8_t b = 1;
uint8_t c = 5;
if(foo == b*c) {}
if(foo == a) {}
if(foo == a + c) {}
if(foo == a + b*c) {}
return 0;
}
只有在最后一次比较时,我才收到编译器警告:“有符号和无符号整数表达式[-Wsign-compare]之间的比较”。
为什么只在最后一种情况下才会发生这种情况?
答案 0 :(得分:4)
由于操作数的类型不同,因此发生了一组隐式转换以达到相同的类型。
对于二进制运算符(移位除外),如果提升的操作数 具有不同的类型,另外一组隐式转换是 应用,通常称为arithmetic conversions,目标是 产生普通类型(也可以通过std :: common_type类型访问 特质)
由于整数类型,此处积分转化适用于:
- 如果任何一个操作数具有范围内的枚举类型,则不执行任何转换:另一个操作数和返回类型必须具有相同的
类型
- 否则,如果其中一个操作数为long double,则另一个操作数将转换为long double
- 否则,如果其中一个操作数为double,则另一个操作数将转换为double
- 否则,如果其中一个操作数为float,则另一个操作数将转换为float
- 否则,操作数具有整数类型(因为bool,char,char8_t,char16_t,char32_t,wchar_t 和无作用域枚举 在这一点上得到了提升),而整体转化是 生成通用类型,如下所示:
- 如果两个操作数都是带符号的,或者都是无符号的,则转换等级较小的操作数将被转换为带有 更大的整数转换排名
- 否则,如果无符号操作数的转换等级大于或等于有符号操作数的转换等级 操作数,有符号操作数将转换为无符号
操作数的类型。- 否则,如果有符号操作数的类型可以表示无符号操作数的所有值,则无符号操作数将转换为 有符号操作数的类型否则,两个操作数都将转换为 有符号操作数类型的无符号对应物。
相同的算术转换也适用于comparison operators。
从这所有的可以得出结论,因为rhs
都是uint8_t
的通用类型将是int,然后因为rhs
是uint32_t
的{ {1}}运算符将为==
。
但由于某种原因,我不知道uint32_t
不会在clang进行时进行最后的转换。请参见godblot中的gcc
运算符的gcc
类型转换
警告也可能是错误的警告,并且发生了转换,就像+
运算符一样。
查看+
如何看到最后一个clang
(cppinsights):
if
更新:
我找不到这两个编译器生成的程序集之间的差异,因此同意@ M.M,因此,IMO,这是一个if(foo == static_cast<unsigned int>(static_cast<int>(a) + (static_cast<int>
(b) * static_cast<int>(c))))
错误。
答案 1 :(得分:0)
这是一个编译器“错误”。详细说明:
通常,有符号和无符号之间的比较取决于实现定义的数量(类型的大小/范围)。例如,USHRT_MAX == -1
在常见的16位系统上为true,在常见的32位系统上为false。 “遗忘”的答案会涉及到更多的技术细节。
您的所有代码示例均定义明确,并且在所有(合格)系统上的行为均相同。
此警告的意图是双重的:
但是,一般而言。编译器的静态分析要整理出第一种情况并不是一件容易的事,更不用说第二种情况了,这很主观。
IMO,对于您的代码,警告是一个错误,因为代码定义明确,没有警告可言。
我个人不启用此警告:我熟悉带符号-无符号比较的规则,并且宁愿避免破坏我的代码以抑制该警告。
相反,有些人宁愿避免在代码中进行所有有符号/无符号的比较,即使定义明确;他们会认为这是一个错误,编译器不会警告您前三个代码示例。
海湾合作委员会往往在警告方面犯了太多错误,但是他们处于无法取悦所有人的境地。