比较8位不同的签名类型(int8_t,uint8_t):结果是否确定?

时间:2016-10-04 16:03:07

标签: c++ c gcc4.9

我运行this simple program

#include <stdint.h>
#include <iostream>
int main() {
    uint8_t x = 100;
    int8_t y = -128;
    if (x < y) {
        std::cout << (int) x << " is less than " << (int) y << std::endl;
    } else {
        std::cout << (int) y << " is less than " << (int) x << std::endl;
    }
}

输出正确:

-128 is less than 100

我最初惊讶地看到没有产生签名警告 然后我很惊讶没有进行错误的转换(-128 - > 255)因此没有得到错误的结果。
然后我读了this

  

1 除了bool,char16_t,char32_t或wchar_t之外的整数类型的prvalue,其整数转换等级(4.13)小于int的等级,可以转换为int类型的prvalue如果int可以表示源类型的所有值;否则,源prvalue可以转换为unsigned int类型的prvalue。 [§4.5]

Link to standard n2356
什么意思“可以转换”?如果发生这种转换,是否由编译器实现,如果该表达式将返回正确的值?

重点是编译器必须搜索转换2个操作数的公共类型,但我没有发现标准中有任何义务做到最好这样这种常见类型能够代表两种输入类型的所有可能值。

注意:我也标记了C,因为这种情况似乎也适用于它 相关问题:Comparison signed and unsigned char。还this

1 个答案:

答案 0 :(得分:3)

是的,结果是确定性的,而不是(编译器)实现定义的。下面是文档here(链接建议here

后C ++ 11的动机(应该可以对其他人做同样的事情)

有必要综合以下所有内容:

  

5.9关系运算符

     
      
  1. [...]

  2.   
  3. 通常的算术转换是在算术或枚举类型的操作数上执行的。

  4.   

要找到通常的算术转换,我们需要转到第5章第9段的内容:

  

许多期望算术或枚举类型操作数的二元运算符会导致转换和产生   结果类型以类似的方式。目的是产生一个通用类型,它也是结果的类型。   此模式称为通常的算术转换,其定义如下:

     
      
  • [...](枚举和浮点类型)
  •   
  • 否则,整体促销(4.5)将同时执行   的操作数即可。[59]然后,以下规则将应用于提升的   操作数:

         
        
    • 如果两个操作数具有相同的类型,则无需进一步转换。
    •   
    • [...]
    •   
  •   

所以,整体推广,引用4.5:

  

除 bool,char16_t,char32_t或wchar_t之外的整数类型的prvalue,其整数转换   如果int可以表示all,则rank(4.13)小于int的rank可以转换为int类型的prvalue   源类型的值;否则,源prvalue可以转换为unsigned类型的prvalue   中间体

所以:
我们有一个关系运算符,将使用通常的算术转换。这些强制应用整体促销。 uint8_tint8_t的完整促销可以int,因此强制应用。

因此,编译器会将uint8_tint8_t之间的比较转换为2 int之间的比较。没有不确定的行为。

虽然有类似的Q / A here(约short类型),但这使我走上了正确的道路。

注意以下矛盾:关系运算符返回一个布尔值(5.9.1),但它们使用通常的算术转换来获取相同类型的2个操作数。但是,这里提出了问题,通常的算术转换的定义说通用类型也是结果的类型,而对于关系运算符则不是这样!

C11不存在矛盾,其中关系运算符返回的结果确实是int。 (谢谢chux)