简体   繁体   English

解释与促销的整数比较

[英]Explain integer comparison with promotion

I'm trying to understand how integer promotion and comparison in and c++ application works. 我试图理解整数推广和比较以及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;
}

Only for the last comparison i get a compiler warning: "comparison between signed and unsigned integer expressions [-Wsign-compare]". 仅在最后的比较中,我得到一个编译器警告:“有符号和无符号整数表达式之间的比较[-Wsign-compare]”。

Why does this only happen in the last case but not in the others? 为什么这只发生在最后一种情况而不是其他情况?

since the type of operands are different a set of implicit conversions take place to reach a common type. 由于操作数的类型不同,因此会发生一组隐式转换以达到共同类型。

For the binary operators (except shifts), if the promoted operands have different types, additional set of implicit conversions is applied, known as usual arithmetic conversions with the goal to produce the common type (also accessible via the std::common_type type trait) 对于二元运算符(除了移位),如果提升的操作数具有不同的类型,则应用另外一组隐式转换,称为通常的算术转换 ,目标是生成公共类型(也可通过std :: common_type类型特征访问)

because of integral types here integral conversions is applied to: 由于积分类型, 积分转换适用于:

  • If either operand has scoped enumeration type, no conversion is performed: the other operand and the return type must have the same 如果任一操作数具有作用域枚举类型,则不执行任何转换:另一个操作数和返回类型必须相同
    type 类型
    • Otherwise, if either operand is long double, the other operand is converted to long double 否则,如果任一操作数为long double,则另一个操作数将转换为long double
    • Otherwise, if either operand is double, the other operand is converted to double 否则,如果任一操作数为double,则另一个操作数将转换为double
    • Otherwise, if either operand is float, the other operand is converted to float 否则,如果任一操作数为float,则另一个操作数将转换为float
    • Otherwise, the operand has integer type (because bool, char, char8_t, char16_t, char32_t, wchar_t , and unscoped enumeration were promoted at this point) and integral conversions are applied to produce the common type, as follows: 否则,操作数具有整数类型(因为此时提升了bool,char,char8_t,char16_t,char32_t,wchar_t和unscoped枚举)并且应用积分转换以生成公共类型,如下所示:
    • If both operands are signed or both are unsigned, the operand with lesser conversion rank is converted to the operand with the greater integer conversion rank 如果两个操作数都是有符号的或两者都是无符号的,则具有较小转换等级的操作数将转换为具有较大整数转换等级的操作数
    • Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of the signed operand, the signed operand is converted to the unsigned 否则,如果无符号操作数的转换等级大于或等于带符号操作数的转换等级,则带符号的操作数将转换为无符号操作数
      operand's type. 操作数的类型。
    • Otherwise, if the signed operand's type can represent all values of the unsigned operand, the unsigned operand is converted to the signed operand's type Otherwise, both operands are converted to the unsigned counterpart of the signed operand's type. 否则,如果带符号操作数的类型可以表示无符号操作数的所有值,则无符号操作数将转换为带符号操作数的类型。否则,两个操作数都将转换为带符号操作数类型的无符号对应项。

The same arithmetic conversions apply to comparison operators too. 相同的算术转换也适用于比较运算符

from all this one can conclude since the rhs are all uint8_t the common type will be int, and then since the rhs is uint32_t the common type of == operator will be uint32_t . 从这一切可以得出结论,因为rhs都是uint8_t ,公共类型将是int,然后由于rhsuint32_t==运算符的常见类型将是uint32_t but for some reason that I have no idea gcc don't do the last conversion while clang does it. 但由于某种原因,我不知道gcc不做最后一次转换,而clang做到了。 see the gcc type conversion for + operator in godblot It also could happen that the warning is a false warning and the conversion took place, as it happened for + operator. godblot中看到+运算符的gcc类型转换也可能发生警告是错误警告并且发生了转换,就像+运算符一样。 See how clang sees the last if ( cppinsights ): 看看clang如何看到最后的ifcppinsights ):

if(foo == static_cast<unsigned int>(static_cast<int>(a) + (static_cast<int> 
(b) * static_cast<int>(c))))

Update: 更新:

I couldn't find a difference in the assembly generated by the two compilers and would agree with @MM so, IMO it's a gcc bug. 我无法找到两个编译器生成的程序集的差别,并且会同意@MM所以,IMO这是一个gcc错误。

It's a compiler "bug". 这是一个编译器“bug”。 To elaborate on this: 详细说明:

  • In general, comparison between signed and unsigned relies on implementation-defined quantities (the sizes/ranges of types). 通常,有符号和无符号之间的比较依赖于实现定义的数量(类型的大小/范围)。 For example USHRT_MAX == -1 is true on common 16-bit systems, and false on common 32-bit systems. 例如, USHRT_MAX == -1在常见的16位系统上为true,在常见的32位系统上为false。 The answer by "oblivion" goes into more technical detail about this. “遗忘”的答案涉及更多技术细节。

  • All of your code examples are well-defined and behave the same on all (conforming) systems. 所有代码示例都是明确定义的,并且在所有(符合标准)系统上的行为相同。

The intent of this warning is twofold: 这个警告的目的是双重的:

  1. to alert you to code that might behave differently on other systems. 提醒您在其他系统上可能表现不同的代码。
  2. to alert you to code that might not behave as the coder intended. 提醒您可能不像编码器那样的代码。

However, in general. 但是,总的来说。 it's not such a simple job for the compiler's static analysis to sort out the first case, let alone the second case which is rather subjective. 对于编译器的静态分析来说,排除第一种情况并不是一件简单的工作,更不用说第二种情况是相当主观的。

IMO the warning, for your code, is a bug because the code is well-defined and there is nothing to warn about. 对于您的代码,IMO警告是一个错误,因为代码定义明确,没有什么可以警告的。

Personally I don't enable this warning: I'm familiar with the rules for signed-unsigned comparison and prefer to avoid mangling my code to suppress the warning. 我个人没有启用此警告:我熟悉签名 - 无符号比较的规则,并希望避免修改我的代码来抑制警告。

Going to the opposite extreme, some people prefer to avoid all signed-unsigned comparisons in their code even when it is well-defined; 对于相反的极端,有些人宁愿避免在代码中进行所有符号无符号比较,即使它的定义很明确; and they would consider it a bug that the compiler doesn't warn about your first three code examples. 他们会认为这是一个错误,编译器没有警告你的前三个代码示例。

GCC has tended to err on the side of warning too much, but they are in the situation that they can't please everyone. 海湾合作委员会倾向于在警告方面犯错误,但他们面临的情况是他们不能取悦所有人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM