I always learn from comments. Sadly, I don’t mean the comments inside the million lines of code I maintain for my day job — they usually don’t exist ;-)
I have had two previous posts dealing with sizeof() being used on a string constant like this:
#define VERSION "1.0.42-beta"
printf ("sizeof(VERSION) = %d\n", sizeof(VERSION));
Several comments were left to make this more better.
Use %z to print a size_t
The first pointed out that sizeof() is not returning a %d integer:
sizeof does not result in an int, so using %d is not correct.
– F W
Indeed, this code should generate a compiler warning on a good compiler. I would normally cast the sizeof() return value to an int like this:
printf ("sizeof(VERSION) = %d\n", (int)sizeof(VERSION));
BUT, I knew that really wasn’t a solution since that code is not portable. An int might be 16-bits, 32-bits or 64-bits (or more?) depending on the system architecture. I often write test code on a PC using Code::Blocks which uses the GNU-C compiler. On that system, I would need to use “%ld” for a long int. When that code is used on an embedded compiler (such as the CCS compiler for PIC42 chips), I need to make that “%d”.
I just figured printf() pre-dates stuff like that and thus you couldn’t do anything about it.
But now I know there is a proper solution — if you have a compiler that supports it. In the comments again…
… when you want to print a
– Sean Patrick Connersize_t
value, using%zu
.
Thank you, Sean Patrick Conner! You have now given me new information I will use from now on. I was unaware of %z. I generally use the website www.cplusplus.com to look up C things, and sure enough, on the printf entry it mentions %z — just in a separate box below the one I always look at. I guess I’d never scrolled down.
This old dog just learned some new tricks!
int var = 123;
printf ("sizeof(var) = %zu\n", sizeof(var));
Thank you very much for pointing this out to me. Unfortunately, the embedded compiler I use for my day job does not support any of the new stuff, and only has a sub-set of printf, but the Windows compiler I use for testing does.
Bonus: printing pointers for fun and profit
I’d previously ran in to this when trying to print out a pointer:
int main()
{
char *ptr = 0x12345678;
printf ("ptr = 0x%x\n", ptr);
return EXIT_SUCCESS;
}
A compiler should complain about that, like this:
warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘char *’ [-Wformat=]
…so I’d just do a bit of casting, to cast the pointer to what %x expects:
printf ("ptr = 0x%x\n", (unsigned int)ptr);
BUT, that assumes an “int” is a certain size. This casting might work find on a 16-bit Arduino, then need to be changed for a 32-bit or 64-bit PC program.
And, the same needs to be done when trying to assign a number (int) to a char pointer. This corrects both issues, but does so the incorrect way:
int main()
{
char *ptr = (char*)0x12345678;
printf ("ptr = 0x%lx\n", (unsigned long)ptr);
return EXIT_SUCCESS;
}
First, I had to cast the number to be a character pointer, else it would not assign to “char *ptr” without a warning.
Second, since %x expects an “unsigned int”, and pointers on this sytem are long, I had to change the printf to use “%lx” for a long version of %x, and cast the “ptr” itself to be an “unsigned long”.
Had I written this initially on a system that uses 16-bit ints (like Arduino, PIC24, etc.), I would have had to do it differently, casting things to “int” instead of “long.”
This always drove me nuts, and one day I wondered if modern C had a way to deal with this. And, indeed, it does: %p
This was something that my old compilers either didn’t have, or I just never learned. I only discovered this within the past five years at my current job. It solves the problems by handling a “pointer” in whatever size it is for the system the code is compiled on. AND it even includes the “0x” prefix in the output:
int main()
{
char *ptr = (char*)0x12345678;
printf ("ptr = %p\n", ptr);
return EXIT_SUCCESS;
}
I suppose when I found there was a “real” way to print pointers I should have expected there was also a real way to print size_t … but it took you folks to teach me that.
And I thank you.
Until next time…
Although technically not great to cast size_t to int, imagine the poor soul that has to read source code that contains a string constant that is so long that it’s size can’t be correctly casted to a 16-bit (signed or unsigned) integer. 32767 or 65535 characters of pure gold? :D
(Are there any C-like compilers (they wouldn’t be actually conforming to the C standard AFAIK, thus C-like) that has integers that has less than 16 bits)?
I doubt it! The C standard says an int is “at least 16-bits” so even the 1980s CoCo C compiler from Microware used 16-bit ints. So my question is, on machines without 16-bit registers, how do they do it? Fake the 16 in software? Where there Commodore C64 C compilers?
It seems like the anti spam thingie has a hard time allowing my comments? Not sure if it’s a bug / slowness or what?
Either way, if what I wrote isn’t just waiting for manual approval, I make another attempt:
Imagine the poor soul who has to read a source code file with sting constant that won’t fit if size_t is casted to a 16-bit integer. 32766 or 65534 characters of famtastic comtemt :D :D
I did see that previous comment, and replied. I wonder what’s broken.
Seems like if I reload the page the comment I made appears. Maybe? Kind of? Sort of? :)
I do not think my hosting company is great with WordPress, which is ironic since they offer it as a “one click” install.
It could also be a browser issue. I’m using Firefox which apparently is only used by a small minority nowadays.