Mohammad Nabil
Mohammad Nabil

Reputation: 105

How C printf function knows the integer size passed?

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

Answers (2)

Oliver Charlesworth
Oliver Charlesworth

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 an int; otherwise, it is converted to an unsigned 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.


1. I'm assuming you have 32-bit ints here.

Upvotes: 8

Petr Skocik
Petr Skocik

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

Related Questions