260

Which format specifier should I be using to print the address of a variable? I am confused between the below lot.

%u - unsigned integer

%x - hexadecimal value

%p - void pointer

Which would be the optimum format to print an address?

jww
  • 97,681
  • 90
  • 411
  • 885
San
  • 3,933
  • 7
  • 34
  • 43

6 Answers6

311

The simplest answer, assuming you don't mind the vagaries and variations in format between different platforms, is the standard %p notation.

The C99 standard (ISO/IEC 9899:1999) says in §7.19.6.1 ¶8:

p The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.

(In C11 — ISO/IEC 9899:2011 — the information is in §7.21.6.1 ¶8.)

On some platforms, that will include a leading 0x and on others it won't, and the letters could be in lower-case or upper-case, and the C standard doesn't even define that it shall be hexadecimal output though I know of no implementation where it is not.

It is somewhat open to debate whether you should explicitly convert the pointers with a (void *) cast. It is being explicit, which is usually good (so it is what I do), and the standard says 'the argument shall be a pointer to void'. On most machines, you would get away with omitting an explicit cast. However, it would matter on a machine where the bit representation of a char * address for a given memory location is different from the 'anything else pointer' address for the same memory location. This would be a word-addressed, instead of byte-addressed, machine. Such machines are not common (probably not available) these days, but the first machine I worked on after university was one such (ICL Perq).

If you aren't happy with the implementation-defined behaviour of %p, then use C99 <inttypes.h> and uintptr_t instead:

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

This allows you to fine-tune the representation to suit yourself. I chose to have the hex digits in upper-case so that the number is uniformly the same height and the characteristic dip at the start of 0xA1B2CDEF appears thus, not like 0xa1b2cdef which dips up and down along the number too. Your choice though, within very broad limits. The (uintptr_t) cast is unambiguously recommended by GCC when it can read the format string at compile time. I think it is correct to request the cast, though I'm sure there are some who would ignore the warning and get away with it most of the time.


Kerrek asks in the comments:

I'm a bit confused about standard promotions and variadic arguments. Do all pointers get standard-promoted to void*? Otherwise, if int* were, say, two bytes, and void* were 4 bytes, then it'd clearly be an error to read four bytes from the argument, non?

I was under the illusion that the C standard says that all object pointers must be the same size, so void * and int * cannot be different sizes. However, what I think is the relevant section of the C99 standard is not so emphatic (though I don't know of an implementation where what I suggested is true is actually false):

§6.2.5 Types

¶26 A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.39) Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements.

39) The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.

(C11 says exactly the same in the section §6.2.5, ¶28, and footnote 48.)

So, all pointers to structures must be the same size as each other, and must share the same alignment requirements, even though the structures the pointers point at may have different alignment requirements. Similarly for unions. Character pointers and void pointers must have the same size and alignment requirements. Pointers to variations on int (meaning unsigned int and signed int) must have the same size and alignment requirements as each other; similarly for other types. But the C standard doesn't formally say that sizeof(int *) == sizeof(void *). Oh well, SO is good for making you inspect your assumptions.

The C standard definitively does not require function pointers to be the same size as object pointers. That was necessary not to break the different memory models on DOS-like systems. There you could have 16-bit data pointers but 32-bit function pointers, or vice versa. This is why the C standard does not mandate that function pointers can be converted to object pointers and vice versa.

Fortunately (for programmers targetting POSIX), POSIX steps into the breach and does mandate that function pointers and data pointers are the same size:

§2.12.3 Pointer Types

All function pointer types shall have the same representation as the type pointer to void. Conversion of a function pointer to void * shall not alter the representation. A void * value resulting from such a conversion can be converted back to the original function pointer type, using an explicit cast, without loss of information.

Note: The ISO C standard does not require this, but it is required for POSIX conformance.

So, it does seem that explicit casts to void * are strongly advisable for maximum reliability in the code when passing a pointer to a variadic function such as printf(). On POSIX systems, it is safe to cast a function pointer to a void pointer for printing. On other systems, it is not necessarily safe to do that, nor is it necessarily safe to pass pointers other than void * without a cast.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 3
    I'm a bit confused about standard promotions and variadic arguments. Do all pointers get standard-promoted to `void*`? Otherwise, if `int*` were, say, two bytes, and `void*` were 4 bytes, then it'd clearly be an error to read four bytes from the argument, non? – Kerrek SB Jan 29 '12 at 17:30
  • 1
    Note that an update to POSIX (POSIX 2013) has removed section 2.12.3, moving most of the requirements to the [`dlsym()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html) function instead. One day I'll write up the change...but 'one day' is not 'today'. – Jonathan Leffler Jun 04 '14 at 18:18
  • Does this answer also apply to pointers to functions? Can they be converted to `void *`? Hmm I see your comment [here](http://stackoverflow.com/questions/9053658/correct-format-specifier-to-print-pointer-address#comment11360489_9053677). Since only one-wat conversion is needed (function pointer to `void *`), it works then? – chux - Reinstate Monica Oct 03 '15 at 13:59
  • 1
    @chux: Strictly, the answer is 'no', but in practice the answer is 'yes'. The C standard does not guarantee that function pointers can be converted to a `void *` and back without loss of information. Pragmatically, there are very few machines where the size of a function pointer is not the same as the size of an object pointer. I don't think the standard provides a method of printing a function pointer on machines where tha conversion is problematic. – Jonathan Leffler Oct 03 '15 at 14:07
  • "and back without loss of information" is not relevant to printing. Does that help? – chux - Reinstate Monica Oct 03 '15 at 14:19
  • @chux: No; if the conversion can't be round-tripped, the value that's printed may not be useful. It'll be _a_ representation of the function pointer, but it might be neither usable nor accurate. For example, if you were on a machine where the function pointer was 128 bits but a void pointer was 64 bits, then you could use `printf("%p\n", (void *)funcptr);` but it really isn't clear that it helps, any more than `printf("%d\n", (int)longvalue);` is reliably useful if `sizeo(int) != sizeof(long)` and the value in `longvalue` is larger than fits into an `int`. – Jonathan Leffler Oct 03 '15 at 18:20
  • @JonathanLeffler: consider `#include int main(void) { int p=9; int* m=&s; printf("%u",m); }` __is it undefined behaviour to print address of variable using `%u` format specifier ?__ Address of variable in most cases is positive so can I use `%u` instead of `%p` ? – Destructor Dec 19 '16 at 16:20
  • On a 64-bit system, you will be printing a 32-bit value with `%u` but your pointer was 64 bits. Yes, it is undefined. If you want to print the pointer using integer formats, use some variation on PRIXPTR as shown in my answer. – Jonathan Leffler Dec 19 '16 at 17:11
  • _It would matter on a machine with a different representation for `char *`._ True, especially on PCs where there were "far" pointers. –  Jan 08 '17 at 12:02
  • One implementation where this was certainly false was the first C implementation. – Antti Haapala -- Слава Україні Mar 19 '17 at 07:28
  • @AnttiHaapala: yes, `%p` arrived in widespread use with the C89/C90 standard. There are lots of other features that weren't in the original Standard I/O library of 1978 or thereabouts (possibly a couple of years earlier than that), but those issues are seldom relevant to anyone any more. When they are an issue, the programmer is usually aware which documentation applies. In those environments, there isn't `long long` or `uintptr_t` or … either. Lots of things were different in the pre-history of C. – Jonathan Leffler Mar 19 '17 at 07:45
76

p is the conversion specifier to print pointers. Use this.

int a = 42;

printf("%p\n", (void *) &a);

Remember that omitting the cast is undefined behavior and that printing with p conversion specifier is done in an implementation-defined manner.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • 3
    Pardon, why omitting the cast is "undefined behavior"? Does this matter address of which variable it is, if all you need is the address, not the value? – valdo Jan 29 '12 at 13:54
  • 11
    @valdo because C says it (C99, 7.19.6.1p8) "p The argument shall be a pointer to void." – ouah Jan 29 '12 at 13:55
  • 14
    @valdo: It's not necessarily the case that all pointers are the same size / representation. – caf Jan 29 '12 at 14:06
38

Use %p, for "pointer", and don't use anything else*. You aren't guaranteed by the standard that you are allowed to treat a pointer like any particular type of integer, so you'd actually get undefined behaviour with the integral formats. (For instance, %u expects an unsigned int, but what if void* has a different size or alignment requirement than unsigned int?)

*) [See Jonathan's fine answer!] Alternatively to %p, you can use pointer-specific macros from <inttypes.h>, added in C99.

All object pointers are implicitly convertible to void* in C, but in order to pass the pointer as a variadic argument, you have to cast it explicitly (since arbitrary object pointers are only convertible, but not identical to void pointers):

printf("x lives at %p.\n", (void*)&x);
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 3
    All *object* pointers are convertible to `void *` (though for `printf()` you technically need the explicit cast, since it's a variadic function). Function pointers aren't necessarily convertible to `void *`. – caf Jan 29 '12 at 13:54
  • @caf: Oh, I didn't know about the variadic arguments - fixed! Thanks! – Kerrek SB Jan 29 '12 at 13:58
  • 2
    Standard C does not require that function pointers be convertible to `void *` and back to function pointer without loss; fortunately, though, POSIX does explicitly require that (noting that it is not part of standard C). So, in practice, you can get away with it (converting `void (*function)(void)` to `void *` and back to `void (*function)(void)`), but strictly it is not mandated by the C standard. – Jonathan Leffler Jan 29 '12 at 14:18
  • 2
    Jonathan and R.: This is all very interesting, but I'm pretty sure we're not trying to print function pointers here, so perhaps this isn't quite the right place to discuss this. I'd much rather see some support here for my insistence to not use `%u`! – Kerrek SB Jan 29 '12 at 16:08
  • OK, deleted my rather irrelevant and wrong comment. Feel free to do the same with yours if you like. And +1 for saying not to use horribly wrong format specifiers like `%u`. I would remove the phrase "strictly speaking" though. IMO it relegates the issue to the domain of language lawyers when it's actually a serious real-world bug to use the wrong specifier. – R.. GitHub STOP HELPING ICE Jan 29 '12 at 16:31
  • I agree that both `%u` and `%lu` are wrong on some machines, and that `%p` is much better than either of those. There are, however, two integer types that you can use reliably - `intptr_t` and `uintptr_t` (though why you'd want to used the signed version, I'm not sure!). See my answer. So, yes - what you say is mostly good. (I removed what I consider the contentious part of the exchange with @R..). – Jonathan Leffler Jan 29 '12 at 17:11
  • @JonathanLeffler: Ah, yes, the venerable `` macros... indeed, worthy of chapter by themselves! – Kerrek SB Jan 29 '12 at 17:26
  • 3
    `%u` and `%lu` are wrong on **all machines**, not some machines. The specification of `printf` is very clear that when the type passed does not match the type required by the format specifier, the behavior is undefined. Whether the size of the types matches (which could be true or false, depending on the machine) is irrelevant; it's the types that must match, and they never will. – R.. GitHub STOP HELPING ICE Jan 29 '12 at 18:09
  • @KerrekSB: consider `#include int main(void) { int p=9; int* m=&s; printf("%u",m); }` __is it undefined behaviour to print address of variable using %u format specifier ?__ Address of variable in most cases is positive so can I use `%u` instead of `%p` ? – Destructor Dec 19 '16 at 16:24
  • 1
    @Destructor: `%u` expects an `unsigned int`, and you are passing an `int *`, so it's UB. – Kerrek SB Dec 19 '16 at 18:20
9

As an alternative to the other (very good) answers, you could cast to uintptr_t or intptr_t (from stdint.h/inttypes.h) and use the corresponding integer conversion specifiers. This would allow more flexibility in how the pointer is formatted, but strictly speaking an implementation is not required to provide these typedefs.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • consider `#include int main(void) { int p=9; int* m=&s; printf("%u",m); }` __is it undefined behaviour to print address of variable using `%u` format specifier ?__ Address of variable in most cases is positive so can I use `%u` instead of `%p` ? – Destructor Dec 19 '16 at 16:27
  • 1
    @Destructor: No, `%u` is a format for `unsigned int` type and cannot be used with a pointer argument to `printf`. – R.. GitHub STOP HELPING ICE Dec 19 '16 at 18:07
6

You can use %x or %X or %p; all of them are correct.

  • If you use %x, the address is given as lowercase, for example: a3bfbc4
  • If you use %X, the address is given as uppercase, for example: A3BFBC4

Both of these are correct.

If you use %x or %X it's considering six positions for the address, and if you use %p it's considering eight positions for the address. For example:

Das_Geek
  • 2,775
  • 7
  • 20
  • 26
Pasha
  • 73
  • 1
  • 2
  • 2
    Welcome to SO. Please take some time to review the other answers, they are explaining clearly a number of details you are overlooking. – AntoineL Feb 18 '20 at 19:35
  • 1
    In particular `%X` is plain wrong. It expects `unsigned int` and it might "work" if the system's pointer size is the same as the integer size, but on today's desktop systems it isn't. The correct way is to use format `%p` *and* cast the pointer to `(void*)`, so none of your solutions is proper. – Weather Vane May 09 '22 at 17:43
0

The standard is %p.

If %x only print parts of the whole address on 64-bit system, use %lx or %llx instead.

LitileXueZha
  • 512
  • 6
  • 11