Why is static_cast on an expression acting distributively?

扶醉桌前 提交于 2019-12-22 05:06:49

问题


I need to take 2 unsigned 8-bit values and subtract them, then add this value to a 32-bit accumulator. The 8-bit subtraction may underflow, and that's ok (unsigned int underflow is defined behavior, so no problems there).

I would expect that static_cast<uint32_t>(foo - bar) should do what I want (where foo and bar are both uint8_t). But it would appear that this casts them first and then performs a 32-bit subtraction, whereas I need it to underflow as an 8-bit variable. I know I could just mod 256, but I'm trying to figure out why it works this way.

Example here: 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);

Output:

diff1 = 11
diff2 = 4294967051
diff3 = 4294967051

I would suspect diff3 would have the same behavior as diff1, but it's actually the same as diff2.

So why does this happen? As far as I can tell the compiler should be subtracting the two 8-bit values and then casting to 32-bit, but that's clearly not the case. Is this something to do with the specification of how static_cast behaves on an expression?


回答1:


For most of the arithmetic operators (including -), the operands undergo the usual arithmetic conversions. One of these conversions is that any value of type narrower than int is promoted to int. (Standard reference: [expr]/10).

So the expression foo - bar becomes (int)foo - (int)bar giving (int)-245. Then you cast that to uint32_t which will give a large positive number.

To get the result you are intending , cast to uint8_t instead of uint32_t. Alternatively, use the modulus operator % on the result of the cast to uint32_t.

It is not possible to do a calculation directly in narrower precision than int




回答2:


The issue is not the static_cast but the subtraction, the operands of additive operators have the usual arithmetic conversions applied to them and in this case the integral promotions which results in both operands of the subtraction being promoted to int:

static_cast<uint32_t>(foo - bar);
                      ^^^   ^^^

On the other hand:

static_cast<uint8_t>(foo - bar);

would produce desired result.

from the draft C++ standard section 5.7 [expr.add] says:

The additive operators + and - group left-to-right. The usual arithmetic conversions are performed for operands of arithmetic or enumeration type.

this results in the integral promotions, section 5 [expr] says:

Otherwise, the integral promotions (4.5) shall be performed on both operands

which results in both operands being converted to int, section 4.5 [conv.prom] says:

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.

and then the static_cast to uint32_t is applied which results in a conversion which is defined as follows in section 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). [

The questions Why must a short be converted to an int before arithmetic operations in C and C++? explains why types smaller than int are promoted for arithmetic operations.



来源:https://stackoverflow.com/questions/27931157/why-is-static-cast-on-an-expression-acting-distributively

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!