skip to Main Content

In the below code snippet, why do we get an output of 600? Two questions will help me understand the behavior.

  1. I specified the type for variable b to be uint8_t, why doesn’t the math operation restrict to the same type?
  2. I thought PRIu8 is the right type to print uint8_t, why isn’t this working?

I was hoping to get the answer 88 which results from looping beyond the range of uint8_t

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

void main()
{

    uint8_t b = 200;
    printf("%" PRIu8 "n",b+b+b);
    printf("%" PRIu8 "n",3*b);

}

gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)

3

Answers


  1. If we take a look at inttypes.h, we find the following:

    # define PRIu8      "u"
    

    So this format specifier doesn’t contain any length modifier. This makes sense in the context of its corresponding argument, as it’s impossible to pass a uint8_t to a variadic function. Because this type has a smaller rank than int, a value of this type will get promoted to int. This promotion also happens in the expressions b+b+b and 3*b.

    If you explicitly use a length modifier for a char, you’ll get the expected result.

    printf("%hhdn",b+b+b);
    printf("%hhdn",3*b);
    
    Login or Signup to reply.
  2. In my opinion it is a library bug.

    In MS Visual Studio the macro PRIu8 is expanded to hhu as it should be and you get the expected result.

    It is interesting to note that if to use clang then if you will write for example

    printf("%" PRIu8 "n",( uint8_t)(b+b+b));
    

    when again you will get the expected result.

    Login or Signup to reply.
  3. In C, whenever you call a function with elipsis (...) arguments, such as printf, all of those arguments will undergo default argument promotions. This means that any smaller integer type will be converted to int and passed that way. So in printf, h type prefixes are irrelevant — they’ll be ignored by printf and have no effect (as the argument must be an int anyways).

    In addition, the same conversion of smaller integer types will happen for any arithmetic operator (like + or *) and the resulting operation will be carried out with int precision, giving an int result.

    To get the expected result, explicitly mask it to the appropriate size:

    printf("%un", (b+b+b) & 0xff);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search