0

I'm wondering why Visual Studio prints FFFFFFFF as the output to the below function and not FF. printf seems to be ignoring the width specifier in the format string why?

To fix it, I either have to add c & 0xff or change c to unsigned char. But I'd still like to understand this unusual behavior.

#include <stdio.h>

int main()
{
    char c = -1;
    printf("%02X\n", c);
}
hookenz
  • 36,432
  • 45
  • 177
  • 286

2 Answers2

3
char c = -1;
printf("%02X\n", c);

This has undefined behavior.

The %X format requires an argument of type unsigned int. You're passing an argument of type char, which is (almost certainly) promoted to int.

So you're printing a value of type int with a value outside the range of the expected type, unsigned int. This is where you get undefined behavior.

(There's no portable way to print a signed integer type in hexadecimal, unless you write your own code to do it. %x and %X, which print hexadecimal, require an unsigned argument. The decimal formats are %d for signed and %u for unsigned.)

Note that type char itself may be unsigned in some implementations so your initialization

char c = -1;

doesn't have undefined behavior, but it can store an implementation-defined value (probably 255) in c.

If you want to print a byte value in hexadecimal, you probably want to use unsigned char rather than plain char. And you'll want to convert it to the expected type when passing it to printf, because unsigned char is also (almost certainly) promoted to (signed) int).

unsigned char c = 255;
printf("c = %02X\n", (unsigned int)c);

If you want to print a char value in hexadecimal, you can use this slightly convoluted code: char c = -1; printf("c = %02X\n", (unsigned char)c);

The cast to unsigned char ensures that the value is is in the range 0..255; ensures that the value is not promoted from char to int. The unsigned char value is promoted to int, which is then treated as an unsigned int value by the %02X format. (int and unsigned int arguments are interchangeable, but only for values in the range of both types.)

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Thanks for the explanation. I was debugging some old code wondering why the field was coming out FFFFFFFF. It's well understood now – hookenz Aug 27 '19 at 01:39
  • @Matt: I was afraid my answer was way too long (I didn't take the time to make it shorter). Glad it was helpful. – Keith Thompson Aug 27 '19 at 02:06
  • 1
    Note, the claim that it is OK to supply a non-negative `int` value for a `%X` specifier is not supported by the Standard, it is a "common sense" interpretation that seems to work on all known systems. – M.M Aug 27 '19 at 02:23
  • @M.M: Well, it's not supported by the normative wording of the standard. [N1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) footnote 41 in 6.2.5 paragraph 9 says: "The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions." (I would greatly prefer it if this were stated normatively.) – Keith Thompson Aug 27 '19 at 04:01
0

In most cases char has 1 byte and never less. Byte also could contain 8 or more bits (usually 8). These values are determined by your compiler, c++ standard and hardware. I highly recommend to read this post

To fix your problem write (unsigned char)c.

Joshua
  • 40,822
  • 8
  • 72
  • 132
mikstime
  • 54
  • 6