I learned a new C thing today.
But first, an old C thing.
When you write “standard C” and want to print a value using printf, you are at the mercy of standard C data types. For example, “%d” is a “Signed decimal integer” and “%u” is an “Unsigned decimal integer.”
There apparently mean the data types “int” and “unsigned int”.
int x;
printf ("x is %d\n", x);
unsinged int y;
printf ("y is %u\n", y);
At my day job, I am using a PIC24 processor, which is a 16-bit chip and is Harvard Architecture, similar to an Arduino UNO processor. When I try to write generic code on a PC using GCC (64-bit compiler), I run in to things like this:
char *ptr = 0x1234;
printf ("ptr is 0x%x\n", ptr);
%x expects an “Unsigned decimal value”. ptr is NOT a “Unsigned decimal value” that %x expects, so it will give a warning like:
warning: initialization of 'char *' from 'int' makes pointer from integer without a cast [-Wint-conversion] warning: format '%x' expects argument of type 'unsigned int', but argument 2 has type 'char *' [-Wformat=]
This seems like a reasonable warning. In the past, I’ve cast the pointer to an unsigned int like this:
char *ptr = 0x1234;
printf ("ptr is 0x%x\n", (unsigned int)ptr);
A 16-bit compiler may be just fine with this, but it would generate warnings on a 32 or 64-bit compiler because the “int” is a “long” or “long long” to them. Thus, different casting is needed.
That makes code non-portable, because printing a long int (“%lu”) expects different things on different architectures. In other words, I can cast my code to compile cleanly on the 16-bit system, but then I get warnings on the 64-bit system. Or vise versa.
…but that’s not what this post is about. Instead, it’s about why I was casting in the first place — to print pointers.
I was unaware that a “%p” had been added specifically for printing pointers. Unfortunately, it was not supported in the 16-bit PIC compiler I am using, so that won’t work.
inttypes.h
Instead, I found a stack overflow post that introduced me to “inttypes.h” and uintptr_t. I was unaware of this and see the casting lets me do something like this:
printf ("Dump (0x%x, %u)\r\n", (uintptr_t)ptr, size);
This will cast the pointer to an unsigned integer value which can then be printed!
On some systems.
There’s still the problem with a %u expecting an “int” but the value might be a “long int” (if it’s a 32-bit or 64-bit pointer).
PRIxWHAT?
It looks like someone thought of this, and my original “non portable printf” casting issue.
I see this file also contains #defines for various printf outputting types such as PRIXPTR, PRIX, PRIU8, and lowercase versions where it makes sense like PRIxPTR. These turn in to quoted strings like “d” or “X” or whatever. Meaning, you could use them to get the output type that matches what you want on the compiler you are using, rather than hard-coding %d.
uint32_t x = 42;
printf ("This is my value: %" PRIu32 "\n", x);
Above, PRIu32 turns in to the appropriate %u for printing a 32-bit value. This might be %u on one system, or %lu on another (depending on the size of “int” on the architecture).
Neat!
That lets me printfs be portable, IF the compiler supports these defines.
…as long as your compiler supports it, that is.
Fortunately, my PIC compiler does, so from now on I’ll stop hard-coding %x when printing pointers, and using those defines when printing stdint types like uint32_t:
void Dump(void *ptr, unsigned int size)
{
printf ("Dump (0x%"PRIXPTR", %u)\r\n", (uintptr_t)ptr, size);
At least, I think I will.
Until next time…
Hi, your code blocks’ font color seems to be the same as their background color, making them unreadable without selecting the text (this was reported over at lobsters, so I’m just letting you know).
Thanks. I’m using one of the built in themes so I’ll have to see if it’s something I can change without having to learn how to edit the code stuff.
I disabled the plug-in for now. It has a way to select different color themes, which may be new. I thought it was just colliding with my white background since it defaults to a dark theme. Changing it to the other themes did not change anything, so I’ll just leave it off for now. Thank you for letting me know about this.