42

pixel_data is a vector of char.

When I do printf(" 0x%1x ", pixel_data[0] ) I'm expecting to see 0xf5.

But I get 0xfffffff5 as though I was printing out a 4 byte integer instead of 1 byte.

Why is this? I have given printf a char to print out - it's only 1 byte, so why is printf printing 4?

NB. the printf implementation is wrapped up inside a third party API but just wondering if this is a feature of standard printf?

1

6 Answers 6

60

You're probably getting a benign form of undefined behaviour because the %x modifier expects an unsigned int parameter and a char will usually be promoted to an int when passed to a varargs function.

You should explicitly cast the char to an unsigned int to get predictable results:

printf(" 0x%1x ", (unsigned)pixel_data[0] ); 

Note that a field width of one is not very useful. It merely specifies the minimum number of digits to display and at least one digit will be needed in any case.

If char on your platform is signed then this conversion will convert negative char values to large unsigned int values (e.g. fffffff5). If you want to treat byte values as unsigned values and just zero extend when converting to unsigned int you should use unsigned char for pixel_data, or cast via unsigned char or use a masking operation after promotion.

e.g.

printf(" 0x%x ", (unsigned)(unsigned char)pixel_data[0] ); 

or

printf(" 0x%x ", (unsigned)pixel_data[0] & 0xffU ); 
Sign up to request clarification or add additional context in comments.

16 Comments

@charles. Thank you for the explanation as to why the leading f's! The third party API that I'm using has an unsigned char type - so I changed my definition for pixel_data to use this instead and get the results I need.
@BeeBand: Be careful, just changing to unsigned char may not be enough. On most platforms unsigned char will promote to int, not unsigned int.
@Charles - when I don't change to unsigned char and just do the cast, I still get those leading f's. I guess I need to both change to unsigned int and use a bitmask as well to ensure it works on all platforms.
@BeeBand: If you use a char that is signed it can hold a negative value, when you cast that to an unsigned int it will be converted to via modulo 2^N arithmetic to a large number (i.e. lots of leading f). I don't know exactly what you want, but if you want to interpret byte values always as unsigned values then you should (as you suggest) use an unsigned char; my previous comment was saying that even if you do this you should still cast the unsigned char explicitly to an unsigned int as otherwise it will (usually) be promoted to an int which is not the correct type for %x.
@BeeBand: I've updated my answer, does this more fully address your question?
|
8

Use %hhx

printf("%#04hhx ", foo); 

2 Comments

sadly I'm using a third party API implementation of printf which doesn't seem to allow the hh formatter. But good to know about - thanks.
This is the correct answer, if your printf implementation supports it.If you're using a third-party printf anyway, consider nanoprintf, which supports this github.com/charlesnicholson/nanoprintf
7

Better use the standard-format-flags

printf(" %#1x ", pixel_data[0] ); 

then your compiler puts the hex-prefix for you.

Comments

3

Then length modifier is the minimum length.

5 Comments

so 1 is the minimum length? I thought length modifier was in bytes.
It is the length in characters.
Sorry, I just don't understand what you mean. Why does what happened imply that the length modifier is the minimum length?
@BeeBand: It's what the docs say. You said you want it at least 1 character long.
I see thanks - that is very useful to know - I've been wrong all these years! But I have decided to go with Charles' answer since he explained why I was seeing the leading f's.
2

Width-specifier in printf is actually min-width. You can do printf(" 0x%2x ", pixel_data[0] & 0xff) to print lowes byte (notice 2, to actually print two characters if pixel_data[0] is eg 0xffffff02).

1 Comment

I think this works only on little edian Processors.
0

Without 0x prefix, an hex value may look strange, so I use also with capital X to print like 0xEA instead of 0Xea:

printf ( "The byte is 0x%hhX", thebyte ); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.