为什么 static_cast 在表达式上是分配性的?
Why is static_cast on an expression acting distributively?
我需要取 2 个无符号的 8 位值并将它们相减,然后将此值添加到 32 位累加器。 8位减法可能会下溢,没关系(unsigned int下溢是定义的行为,所以没有问题)。
我希望 static_cast<uint32_t>(foo - bar)
应该做我想做的(其中 foo
和 bar
都是 uint8_t
)。但看起来这会先转换它们,然后 然后 执行 32 位减法,而我需要它作为 8 位变量下溢。我知道我可以 mod 256,但我想弄清楚 为什么 它以这种方式工作。
此处示例:https://ideone.com/TwOmTO
uint8_t foo = 5;
uint8_t bar = 250;
uint8_t diff8bit = foo - bar;
uint32_t diff1 = static_cast<uint32_t>(diff8bit);
uint32_t diff2 = static_cast<uint32_t>(foo) - static_cast<uint32_t>(bar);
uint32_t diff3 = static_cast<uint32_t>(foo - bar);
printf("diff1 = %u\n", diff1);
printf("diff2 = %u\n", diff2);
printf("diff3 = %u\n", diff3);
输出:
diff1 = 11
diff2 = 4294967051
diff3 = 4294967051
我怀疑 diff3
的行为与 diff1
相同,但实际上与 diff2
.
相同
那么为什么会这样呢?据我所知,编译器应该减去两个 8 位值,然后转换为 32 位值,但事实显然不是这样。这与 static_cast
如何在表达式上表现的规范有关吗?
问题不是 static_cast 而是减法,加法运算符的操作数应用了通常的算术转换,在这种情况下,整数提升导致减法的两个操作数都被提升为整数:
static_cast<uint32_t>(foo - bar);
^^^ ^^^
另一方面:
static_cast<uint8_t>(foo - bar);
会产生预期的结果。
来自 C++ 标准草案部分 5.7
[expr.add] 说:
The additive operators + and - group left-to-right. The usual arithmetic conversions are performed for
operands of arithmetic or enumeration type.
这导致积分提升,第 5
[expr] 部分说:
Otherwise, the integral promotions (4.5) shall be performed on both operands
这导致两个操作数都被转换为 int,第 4.5
[conv.prom] 部分说:
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.
,然后应用 static_cast 到 uint32_t,这会导致转换,定义如下 4.7
[conv.integral]:
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source
integer (modulo 2n where n is the number of bits used to represent the unsigned type). [
问题 Why must a short be converted to an int before arithmetic operations in C and C++? 解释了为什么小于 int 的类型被提升为算术运算。
对于大多数算术运算符(包括-
),操作数会进行通常的算术转换。这些转换之一是将任何类型窄于 int
的值提升为 int
。 (标准参考:[expr]/10
)。
所以表达式 foo - bar
变成 (int)foo - (int)bar
给出 (int)-245
。然后你将它转换为 uint32_t
这将给出一个大的正数。
要获得您想要的结果,请转换为 uint8_t
而不是 uint32_t
。或者,对转换为 uint32_t
.
的结果使用取模运算符 %
无法以比 int
更窄的精度直接进行计算
我需要取 2 个无符号的 8 位值并将它们相减,然后将此值添加到 32 位累加器。 8位减法可能会下溢,没关系(unsigned int下溢是定义的行为,所以没有问题)。
我希望 static_cast<uint32_t>(foo - bar)
应该做我想做的(其中 foo
和 bar
都是 uint8_t
)。但看起来这会先转换它们,然后 然后 执行 32 位减法,而我需要它作为 8 位变量下溢。我知道我可以 mod 256,但我想弄清楚 为什么 它以这种方式工作。
此处示例:https://ideone.com/TwOmTO
uint8_t foo = 5;
uint8_t bar = 250;
uint8_t diff8bit = foo - bar;
uint32_t diff1 = static_cast<uint32_t>(diff8bit);
uint32_t diff2 = static_cast<uint32_t>(foo) - static_cast<uint32_t>(bar);
uint32_t diff3 = static_cast<uint32_t>(foo - bar);
printf("diff1 = %u\n", diff1);
printf("diff2 = %u\n", diff2);
printf("diff3 = %u\n", diff3);
输出:
diff1 = 11
diff2 = 4294967051
diff3 = 4294967051
我怀疑 diff3
的行为与 diff1
相同,但实际上与 diff2
.
那么为什么会这样呢?据我所知,编译器应该减去两个 8 位值,然后转换为 32 位值,但事实显然不是这样。这与 static_cast
如何在表达式上表现的规范有关吗?
问题不是 static_cast 而是减法,加法运算符的操作数应用了通常的算术转换,在这种情况下,整数提升导致减法的两个操作数都被提升为整数:
static_cast<uint32_t>(foo - bar);
^^^ ^^^
另一方面:
static_cast<uint8_t>(foo - bar);
会产生预期的结果。
来自 C++ 标准草案部分 5.7
[expr.add] 说:
The additive operators + and - group left-to-right. The usual arithmetic conversions are performed for operands of arithmetic or enumeration type.
这导致积分提升,第 5
[expr] 部分说:
Otherwise, the integral promotions (4.5) shall be performed on both operands
这导致两个操作数都被转换为 int,第 4.5
[conv.prom] 部分说:
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.
,然后应用 static_cast 到 uint32_t,这会导致转换,定义如下 4.7
[conv.integral]:
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type). [
问题 Why must a short be converted to an int before arithmetic operations in C and C++? 解释了为什么小于 int 的类型被提升为算术运算。
对于大多数算术运算符(包括-
),操作数会进行通常的算术转换。这些转换之一是将任何类型窄于 int
的值提升为 int
。 (标准参考:[expr]/10
)。
所以表达式 foo - bar
变成 (int)foo - (int)bar
给出 (int)-245
。然后你将它转换为 uint32_t
这将给出一个大的正数。
要获得您想要的结果,请转换为 uint8_t
而不是 uint32_t
。或者,对转换为 uint32_t
.
%
无法以比 int