Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is static_cast on an expression acting distributively?

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?

like image 723
Joel Geddert Avatar asked Jan 13 '15 20:01

Joel Geddert


People also ask

What is the point of static_cast?

The static_cast operator can be used for operations such as converting a pointer to a base class to a pointer to a derived class.

What happens when you perform a static_cast?

static_cast is the first cast you should attempt to use. It does things like implicit conversions between types (such as int to float , or pointer to void* ), and it can also call explicit conversion functions (or implicit ones).

What happens when static_cast fails?

As we learnt in the generic types example, static_cast<> will fail if you try to cast an object to another unrelated class, while reinterpret_cast<> will always succeed by "cheating" the compiler to believe that the object is really that unrelated class.

What is the difference between Dynamic_cast and static_cast?

Static casting is done by the compiler: it treats the result as the target type, no matter what. You do this when you're absolutely sure about the argument being of the target type. Dynamic casting is done at runtime, and thus requires runtime type information.


1 Answers

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

like image 79
M.M Avatar answered Oct 13 '22 01:10

M.M