解释促销的整数比较

时间:2019-06-27 18:30:35

标签: c++ integer-promotion

我正在尝试了解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]之间的比较”。

为什么只在最后一种情况下才会发生这种情况?

2 个答案:

答案 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,然后因为rhsuint32_t的{ {1}}运算符将为==。 但由于某种原因,我不知道uint32_t不会在clang进行时进行最后的转换。请参见godblot中的gcc运算符的gcc类型转换 警告也可能是错误的警告,并且发生了转换,就像+运算符一样。 查看+如何看到最后一个clangcppinsights):

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。 “遗忘”的答案会涉及到更多的技术细节。

  • 您的所有代码示例均定义明确,并且在所有(合格)系统上的行为均相同。

此警告的意图是双重的:

  1. 提醒您代码在其他系统上的行为可能不同。
  2. 警告您可能无法达到编码人员预期目的的代码。

但是,一般而言。编译器的静态分析要整理出第一种情况并不是一件容易的事,更不用说第二种情况了,这很主观。

IMO,对于您的代码,警告是一个错误,因为代码定义明确,没有警告可言。

我个人不启用此警告:我熟悉带符号-无符号比较的规则,并且宁愿避免破坏我的代码以抑制该警告。

相反,有些人宁愿避免在代码中进行所有有符号/无符号的比较,即使定义明确;他们会认为这是一个错误,编译器不会警告您前三个代码示例。

海湾合作委员会往往在警告方面犯了太多错误,但是他们处于无法取悦所有人的境地。