Reputation: 105
In the following sample code, how did printf knew the size that shall be printed for uint8_t while the mentioned format is only "0x%x" and passd type is uint32_t? how did printf know that in first call it must print 4 bytes and the second call it must only print 1 byte?
uint32_t X = 0xAABBCCDD;
printf("uint32_t 0x%x\n", (uint32_t) X);
printf("uint8_t 0x%x\n", (uint8_t) X);
Output
uint32_t 0xaabbccdd
uint8_t 0xdd
Upvotes: 2
Views: 562
Reputation: 272752
It doesn't know. In both cases you're giving printf
an [unsigned] int
, due to the default argument promotions. Your code is equivalent to this:1
printf("uint32_t 0x%x\n", (unsigned int)(uint32_t) X);
printf("uint8_t 0x%x\n", (int)(uint8_t) X);
The promotion rule is:
[6.3.1.1] If an
int
can represent all values of the original type [...], the value is converted to anint
; otherwise, it is converted to anunsigned int
.
The only rule that printf
follows at this point is to not print leading zeros.
Note that mapping a signed int
to %x
is technically undefined behaviour.
int
s here.
Upvotes: 8
Reputation: 60143
In
printf("uint8_t 0x%x\n", (uint8_t) X);
uint8_t
is definitely a lower-ranking type than int
, and so uint8_t
will be promoted to int
and "%x"
will work.
//potentially invokes UB depending on platform
printf("uint32_t 0x%x\n", (uint32_t) X);
is nonportable code. In theory, you don't know what real type uint32_t
is and so you should be using the PRIx32
macro from inttypes.h
. For consistency/simplicity's sake, you can use PRIx8
for uint8_t
too.
#include <inttypes.h>
#include <stdio.h>
int main()
{
uint32_t X = 0xAABBCCDD;
printf("uint8_t 0x%" PRIx8 "\n", (uint8_t) X);
printf("uint32_t 0x%" PRIx32 "\n", (uint32_t) X);
}
Upvotes: 2