比较不同符号的 8 位类型 (int8_t, uint8_t):结果是确定性的吗?
Comparing 8 bits types of different signedness (int8_t, uint8_t): is result deterministic?
#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
[...]
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_t
和 int8_t
的积分促销可以 int
,因此 必须 应用。
因此auint8_t
和int8_t
之间的比较被编译器转化为2int
之间的比较。没有不确定的行为。
有一个类似的 Q/A here(虽然大约是 short
类型),这让我走上了正确的道路。
尽管注意以下矛盾:关系运算符return 一个布尔值 (5.9.1),但它们使用通常的算术转换来获得 2相同类型的操作数。但是,问题来了,通常算术转换的定义说公共类型也是结果的类型,关系运算符不是这样的!
C11 不存在矛盾,其中关系运算符 return 的结果确实是 int
。 (感谢 chux)
#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
[...]
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_t
和 int8_t
的积分促销可以 int
,因此 必须 应用。
因此auint8_t
和int8_t
之间的比较被编译器转化为2int
之间的比较。没有不确定的行为。
有一个类似的 Q/A here(虽然大约是 short
类型),这让我走上了正确的道路。
尽管注意以下矛盾:关系运算符return 一个布尔值 (5.9.1),但它们使用通常的算术转换来获得 2相同类型的操作数。但是,问题来了,通常算术转换的定义说公共类型也是结果的类型,关系运算符不是这样的!
C11 不存在矛盾,其中关系运算符 return 的结果确实是 int
。 (感谢 chux)