Please do not use %x for pointers
I often see code like this:
printf(“Address of foo: %x\n”, &foo);
The intent here is to print the address in hexadecimal format. Good plan; bad execution.
First, here’s one possible output:
Address of foo: 123456
Is this decimal (%u), hex (%x), or octal (%o)? I can’t tell from the output; for all I know, the person who wrote that line is a real newbie and used %i or %d. (That would be even worse for really high addresses, as they will then be formatted as negative numbers.)
So the author changes the line to:
printf(“Address of foo: 0x%x\n”, &foo);
Now the output has the 0x prefix, making clear that it’s hex, but there’s still a bug here. The bug is that %x is not the correct formatter for pointers.
The type expected by %x is unsigned int
. For the past decade or so, this has not been a problem because on all PCs, including Macs, the size of a pointer has been equal to the size of an int.
But over the past couple years and the next couple years, there’s a transition underway to LP64, wherein long int
s and pointers are 64-bit. Plain int
s won’t be; they’ll still be 32 bits. This means that you’ll get funky results, and possibly crashes (with %s, %n, and %@), if you’re using %x for your pointers.
You could use %lx (unsigned long int
), but it’s still the wrong type. There is a formatter specifically for pointers: %p. It even provides the “0x” prefix for you.
printf(“Address of foo: %p\n”, &foo);
Address of foo: 0x1e240
So, in order to make your code both more stable and more future-proof, please use %p, not %x or %lx, for formatting your pointers.
January 23rd, 2007 at 23:46:56
So true. %p forever.
While we’re sharing development practices, I find it really helpful, especially on a large codebase with spammy log messages, to prefix my debug logs with the name of the file they’re in (and possibly the line number as well). Then I can use Console.app’s filtering support and just see my log messages.
January 24th, 2007 at 00:20:20
Even better, use __FILE__ and __LINE__:
fprintf(stderr, “%s:%u: Address of foo: %p\n”, __FILE__, __LINE__, &foo);
This makes it easy to copy and paste the debug line to some other place in the file, or to another file.
January 24th, 2007 at 21:32:09
Hm, we could make AILog() [and equivalents elsewhere] do that automatically… might be *too* noisy, though.
January 24th, 2007 at 23:19:58
Evan: I assume you mean the __FILE__/__LINE__ magic, as doing correct s/%x/%p/ on every AILog is impossible, and doing it unconditionally is unreasonable.
(For those who don’t know, AILog is a macro in Adium’s source code that directs the output to a debug log window that only exists in betas and trunk builds, as opposed to stderr/console.log.)
January 25th, 2007 at 09:05:12
Hah, yes, ‘that’ referred to prepending __FILE__:__LINE__. On second thought, that would make a giant mess of our incoming libgaim debugging, because it all routes through a single function, adiumGaimDebug().
Still, it makes sense in a sizable project to have an easy way to include such information in a log.
(I failed the spam prevention, forgetting to fix it. Went back to try again and was told this was a duplicate comment. Guess it must have entered a verification queue — you can ignore the previous attempt).
January 25th, 2007 at 15:29:01
Currently, Negative Turing Test (the spam-prevention thing) blocks failed comments by marking them as spam (ostensibly for plug-ins like Akismet). This blocks them, but causes the problem you described. One of the things on the to-do list is a way to simply delete the comment if it fails the test.