A: 

I usually use %x to display pointers. I suppose that isn't portable to 64-bit systems, but it works fine for 32-bitters.

I'll be interested in seeing what answers there are for portable solutions, since pointer representation isn't exactly portable.

T.E.D.
My main system is actually a 64-bit one, so %x doesn't really cut it. Avoiding this kind of problem is why I want to use %p.
Florian
`%#016lx` should work on whatever system your on, a pointer is guaranteed to fit inside a long. (I think) BTW that is the letter 'l' not 1 the number before the 'x'.
Joe D
@Joe D - VS2005 disagrees. It gives me warnings about possible lost data unless I use something like ULONG_PTR instead. Also see the comment left by AProgrammer on the accepted answer. Of course VS isn't exactly known as a paragon of compliance...
T.E.D.
Oh, I forgot to mention the fact that it doesn't work on 64-bit MSVC. I think the both the 32-bit and 64-bit version warn about it.
Joe D
A: 

It's easy to solve if you cast the pointer to a long type. The problem is this won't work on all platforms as it assumes a pointer can fit inside a long, and that a pointer can be displayed in 16 characters (64 bits). This is however true on most platforms.

so it would become:

printf("%016lx", (unsigned long) ptr);
Tony Lambert
I do not have the right machine / OS at hand to confirm, but I think that under 64-bit windows, pointers are 64bit while long are 32 bits, breaking your assumption.So, unless I am mistaken, what you suggest would break on at least one major platform.
Florian
If portability to windows is important, relying on C99 features is probably not the thing to do.
AProgrammer
typically on a 64 bit platform, ints are 32 bits and longs are 64 bits. If this is a problem on your platform use a long long.
Tony Lambert
Actually, I think pointers a guaranteed to fit inside a long. The only implementation that doesn't conform to this is MSVC (64-bit).
Joe D
A: 

As your link suggests already, the behaviour is undefined. I don't think there's a portable way of doing this as %p itself depends on the platform you're working on. You could of course just cast the pointer to an int and display it in hex:

printf("0x%016lx", (unsigned long)ptr);
groovingandi
A: 

Maybe this will be interesting (from a 32-bit windows machine, using mingw):

rjeq@RJEQXPD /u
$ cat test.c
#include <stdio.h>

int main()
{
    char c;

    printf("p: %016p\n", &c);
    printf("x: %016llx\n", (unsigned long long) (unsigned long) &c);

    return 0;
}

rjeq@RJEQXPD /u
$ gcc -Wall -o test test.c
test.c: In function `main':
test.c:7: warning: `0' flag used with `%p' printf format

rjeq@RJEQXPD /u
$ ./test.exe
p:         0022FF77
x: 000000000022ff77

As you can see, the %p version pads with zeros to the size of a pointer, and then spaces to the specified size, whereas using %x and casts (the casts and format specifier are highly unportable) uses only zeros.

Rodrigo Queiro
Interesting. It confirms that %016p" isn't portable, since on my machine (64-bit linux) it pads purely with 0s, not with spaces.
Florian
+7  A: 

#include <inttypes.h>

#include <stdint.h>

printf("%016"PRIxPTR"\n", (uintptr_t)ptr);

but it won't print the pointer in the implementation defined way (says DEAD:BEAF for 8086 segmented mode).

AProgrammer
Interesting. This is the first time I see this PRIxPTR notation. Is this standard, or gcc specific? If standard, which standard? C89 or C99?
Florian
Standard in C99. The macro PRIxPTR is defined in <inttypes.h>. The uintptr_t type is defined in <stdint.h>.
AProgrammer
Let me make sure I got this straight. The reason what I tried to do is not portable is because not all platforms display pointers as 0x..... Because of this padding with 0s is not portable.On the other hand, printf("%016"PRIxPTR", (uintptr_t)ptr); will on all platforms print my pointer with the right lenght, formated as a 0x... number, padded with 0s, without unsafe casting.
Florian
Right. But you depend on C99 -- Microsoft compilers and runtimes support it badly from what I read here and elsewhere (I'm a Unix guy), and some gcc packaging for Windows are reusing the Microsoft run-time. BTW, you won't get the 0x prefix (put it yourself or use a # flag, but note that the flag won't put it for pointers which are converted to 0 -- usually NULL pointers).
AProgrammer
Makes sense. And as Of C89, there is no portable way of doing this?
Florian
It was quite a common practice in C89 to assume that `unsigned long` was able to contains a pointer without loss. Microsoft broke that practice by the choice of the LLP64 Windows 64 bits (while all other systems I know of had chosen LP64 or even ILP64 years before). So I know of no sure way which works on common systems. Defining your own inttypes.h is probably the easiest thing to do (after all, that possibility is one probable reason for which there are macros and not new format for the stdint.h types).
AProgrammer
But what is BEAF?
Artelius
@Artelius, one of the words writable using only letters which are hexadecimal digit (see http://nedbatchelder.com/text/hexwords.html).
AProgrammer
+3  A: 

Use:

#include <inttypes.h>

printf("0x%016" PRIXPTR "\n", (uintptr_t) pointer);

Or use another variant of the macros from that header.

Also note that some implementations of printf() print a '0x' in front of the pointer; others do not (and both are correct according to the C standard).

Jonathan Leffler
Note that formally you need to cast to uintptr_t.
AProgrammer
Yup - thanks for the reminder. Fixed in the answer.
Jonathan Leffler
Or you could use `"%#016" PRIxPTR` instead, the `#` says to display the base for octal and hexadecimal.
Joe D
@Joe: you are right - you could use the '#', but that prints 0x01ab or 0X01AB and I don't like either of those notations: I like 0x01AB. What I wrote gets me what I like and not what I dislike.
Jonathan Leffler