0

Here is the code:

#include <stdio.h>
#include <stdint.h>

int main()
{
  uint8_t ui8 = 0xff;
  printf(" %x\n", ui8);
  printf(" %x\n", (uint8_t)24);
  printf(" %x\n", ui8 << (uint8_t)24);
}

The output is :

 ff
 18
 ff000000

The question is: If I have two uint8_t variables why the result is "promoted" to a higher rank. If it is not promoted, why do I get such a big number. I test it no MinGW win7-64bit platform

klutt
  • 30,332
  • 17
  • 55
  • 95
Hairi
  • 3,318
  • 2
  • 29
  • 68
  • 1
    `printf(" %x\n", (uint8_t)(ui8 << 24));` -- and the value of type `uint8_t` is still going to be converted (to `int`) anyway. – pmg Jul 12 '17 at 12:10
  • Why do you want to shift an 8-bit variable 24 steps? – klutt Jul 12 '17 at 12:14
  • @klutt To compose 32-bit value from 4 byte (serial communication) data buffer. Kind of parsing – Hairi Jul 13 '17 at 07:49

2 Answers2

3

What happens is something called usual arithmetic conversion which leads to integer promotion for both arguments of the << operator.

If you instead of using the shift expression directly in the printf argument, and instead stored it in a uint8_t variable, then the result would be zero. However when you call printf you would instead have a default argument promotion which would turn the uint8_t variable into an int. But that would lead to another problem because even though the format "%x" expects an int (an unsigned int actually, see e.g. this printf and family reference) the data is actually an uint8_t. That means you have mismatched format specifier and argument, leading to undefined behavior. The correct format specifier to print an uint8_t is "%hhx", or better yet use the PRI8x macro:

uint8_t result = ...
printf("%" PRI8x "\n", result);

See e.g. this format macro reference.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • But I see this: "If both operands have the same type, then no further conversion is needed.". Then how come they are still converted to int? – Hairi Jul 12 '17 at 12:59
  • @Hairi Where do you see that? None of my links say that. – Some programmer dude Jul 12 '17 at 13:04
  • Here: https://stackoverflow.com/questions/50605/signed-to-unsigned-conversion-in-c-is-it-always-safe Bullet #1 – Hairi Jul 12 '17 at 13:05
  • 1
    @Hairi That answer is missing a little bit of preamble, namely a section saying "Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands", where the "following rules" is the list you read. That means the integer promotion is done *first* and *then* if the types are the same no more conversions are made. – Some programmer dude Jul 12 '17 at 13:10
3

Both arguments of << are converted to int prior to the evaluation, despite the fact that you've attempted to force the issue with (uint8_t)24.

This is necessarily true since uint8_t is narrower than an int on any platform.

So the result, ff000000, you observe is consistent with an int being at least 32 bits wide on your platform.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483