解释整数与提升的比较 我试图理解C++中的整数提升和比较是如何工作的。p> #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; } #包括 内部主(空) { uint32_t foo=20; uint8_t a=2; uint8_t b=1; uint8_t c=5; 如果(foo==b*c){} 如果(foo==a){} 如果(foo==a+c){} 如果(foo==a+b*c){} 返回0; }

解释整数与提升的比较 我试图理解C++中的整数提升和比较是如何工作的。p> #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; } #包括 内部主(空) { uint32_t foo=20; uint8_t a=2; uint8_t b=1; uint8_t c=5; 如果(foo==b*c){} 如果(foo==a){} 如果(foo==a+c){} 如果(foo==a+b*c){} 返回0; },c++,integer-promotion,C++,Integer Promotion,仅在最后一次比较中,我收到一条编译器警告:“有符号和无符号整数表达式之间的比较[-Wsign compare]” 为什么这只发生在最后一种情况下,而不发生在其他情况下?由于操作数的类型不同,因此会进行一组隐式转换以达到一个公共类型 对于二进制运算符(移位除外),如果提升的操作数 如果具有不同的类型,则需要额外的隐式转换集 应用,如往常所知,目标是 生成公共类型(也可通过std::common_类型访问 (特征) 由于这里的积分类型,积分转换应用于: 如果任一操作数具有作用域枚举类型,则不执行任

仅在最后一次比较中,我收到一条编译器警告:“有符号和无符号整数表达式之间的比较[-Wsign compare]”


为什么这只发生在最后一种情况下,而不发生在其他情况下?

由于操作数的类型不同,因此会进行一组隐式转换以达到一个公共类型

对于二进制运算符(移位除外),如果提升的操作数 如果具有不同的类型,则需要额外的隐式转换集 应用,如往常所知,目标是 生成公共类型(也可通过std::common_类型访问 (特征)

由于这里的积分类型,积分转换应用于:

  • 如果任一操作数具有作用域枚举类型,则不执行任何转换:另一个操作数和返回类型必须具有相同的值
    类型
    • 否则,如果任一操作数为长双精度,则另一个操作数将转换为长双精度
    • 否则,如果任一操作数为双精度,则另一个操作数将转换为双精度
    • 否则,如果任一操作数为浮点,则另一个操作数将转换为浮点
    • 否则,操作数为整数类型(因为bool、char、char8、char16、char32、wchar和unscope枚举 此时已升级)和积分转换 应用生成通用类型,如下所示:
    • 如果两个操作数都有符号或都无符号,则转换秩较小的操作数将转换为具有 更大的整数转换秩
    • 否则,如果无符号操作数的转换秩大于或等于有符号操作数的转换秩 操作数,有符号操作数转换为无符号操作数
      操作数的类型
    • 否则,如果有符号操作数的类型可以表示无符号操作数的所有值,则无符号操作数将转换为 有符号操作数的类型否则,两个操作数都将转换为 有符号操作数类型的无符号对应项
同样的算术转换也适用于

从所有这些可以得出结论,因为
rhs
都是
uint8\u t
,公共类型将是int,然后因为
rhs
uint32\u t
=
运算符的公共类型将是
uint32\u t
。 但是由于某种原因,我不知道在clang执行最后一次转换时,gcc不执行最后一次转换。请参阅中的
+
运算符的
gcc
类型转换 该警告也可能是错误警告,并且发生了转换,就像对
+
运算符发生的那样。 查看
clang
如何查看最后一个
if
():

if(foo==static_cast(静态_cast(a)+(静态_cast
(b) *静态(c)))
更新:

我在两个编译器生成的程序集中找不到差异,我同意@M.M,因此,我认为这是一个
gcc
错误。

这是一个编译器“错误”。要详细说明这一点:

  • 通常,有符号和无符号之间的比较依赖于实现定义的数量(类型的大小/范围)。例如,
    USHRT\u MAX==-1
    在普通16位系统上为真,在普通32位系统上为假。“遗忘”一词的答案涉及到更多的技术细节

  • 您的所有代码示例都定义良好,在所有(一致性)系统上的行为都相同

此警告有两个目的:

  • 提醒您注意在其他系统上可能表现不同的代码
  • 提醒您注意可能与编码器预期行为不符的代码
  • 然而,总的来说。对于编译器的静态分析来说,整理第一种情况并不是一件简单的工作,更不用说第二种情况了,这是相当主观的

    在我看来,对于您的代码来说,警告是一个bug,因为代码定义良好,没有什么需要警告的

    就我个人而言,我不启用此警告:我熟悉有符号-无符号比较的规则,并且更愿意避免损坏代码以抑制此警告

    相反,有些人宁愿在代码中避免所有有符号-无符号比较,即使它是定义良好的;他们会认为编译器不警告你的前三个代码例子。p>
    GCC倾向于在警告方面犯太多的错误,但他们的处境是无法取悦所有人。

    b*c
    a+c
    a+b*c
    都被提升为
    int
    s。由于某些原因,您的编译器仅对其中一个发出警告。哪个编译器、哪个版本以及哪个命令行开关?@EricPostpischil,这在g++6.3.0中可以通过
    -Wall
    重现。在g++7.4.0中,“不执行转换”和“不警告执行转换”之间也有区别。这个问题只是提供了缺乏警告的证据,而不是没有进行转换。为了提供编译器没有实际执行所需转换的证据,有必要检查输出代码(汇编程序等)。@Peter您是对的,必须检查汇编程序。也许这个警告是错误的。我编辑我的声明这不是一个大惊喜,未签名的被提升为签名的?如果没有C++律师学位,我会想说这是根本问题。
    if(foo == static_cast<unsigned int>(static_cast<int>(a) + (static_cast<int> 
    (b) * static_cast<int>(c))))