比较不同符号的 8 位类型 (int8_t, uint8_t):结果是确定性的吗?

Comparing 8 bits types of different signedness (int8_t, uint8_t): is result deterministic?

我运行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 A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int. [§ 4.5]

Link to standard n2356
可以转换”是什么意思?是否会发生此转换以及此表达式是否会 return 正确值是否取决于编译器实现?

关键是编译器 搜索将 2 个操作数转换为的通用类型,但我没有发现标准中有任何义务 尽最大努力 以便此通用类型能够表示这两种输入类型的所有可能值。

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

是的,结果是确定性的,而不是(编译器的)实现定义的。 Here follows the motivation for C++11 (it should be possible to do the same for other), 按照文档 here (link suggested here)

必须结合以下所有内容:

5.9 Relational operators

  1. [...]

  2. The usual arithmetic conversions are performed on operands of arithmetic or enumeration type.

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

Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are defined as follows:

  • [...] (Enumeration and floating point types)
  • Otherwise, the integral promotions (4.5) shall be performed on both operands.[59] Then the following rules shall be applied to the promoted operands:

    • If both operands have the same type, no further conversion is needed.
    • [...]

所以,积分提升,引用自4.5:

A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.

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

因此auint8_tint8_t之间的比较被编译器转化为2int之间的比较。没有不确定的行为。

有一个类似的 Q/A here(虽然大约是 short 类型),这让我走上了正确的道路。

尽管注意以下矛盾:关系运算符return 一个布尔值 (5.9.1),但它们使用通常的算术转换来获得 2相同类型的操作数。但是,问题来了,通常算术转换的定义说公共类型也是结果的类型,关系运算符不是这样的!

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