3

I have an int pointer that points at the address of another int.

When printing the pointer with the format specifier %p (as suggested by many answers on Stack Overflow), it's printed with a hexadecimal representation.

How can I print a pointer's value with with a decimal representation?


Code Sample

I have figured out one can maybe use %zu from this answer.

int i = 1;
int *p = &i;
printf("Printing p: %%p = %p, %%zu = %zu\n", p, p);

When I run that code using https://onlinegdb.com/EBienCIJnm

  • It actually prints the correct value in decimal
  • But it also outputs a compiler warning
warning: format ‘%zu’ expects argument of type ‘size_t’, but argument 3 has type ‘int *’ [-Wformat=]                                                                 
Printing p: %p = 0x7ffee623d8c4, %zu = 140732759529668

Is there a way to printf a pointer's value with a decimal representation, without compiler warnings?

Intrastellar Explorer
  • 3,005
  • 9
  • 52
  • 119
  • `unsigned long addr = (unsigned long)p`; `printf("Printing addr: %lu\n",addr);` any problem with this? – IrAM Jan 17 '21 at 03:14
  • Yeah looks like `%lu` paired with a cast to `(unsigned long)` works as well (https://onlinegdb.com/OpOSsz6Oq). I also like it because it doesn't require a `#include` of `` and/or `` as the other answers do. @IrAM, is this a platform-independent solution (since it requires pointers to be the size of an `unsigned long`)? Seems from [this Quora answer](https://qr.ae/pNmnvI), it's not always the size of `unsigned long` – Intrastellar Explorer Jan 17 '21 at 20:09
  • I am not 100% sure about the portability, but my idea is choose the longest type available based on platform, so that you can represent address properly in decimal. I guess for any platform following will be true `short <= int <= long <= long long`. – IrAM Jan 18 '21 at 02:23

2 Answers2

8

Convert to the uintptr_t type defined in <stdint.h> and format with the PRIuPTR specifier defined in <inttypes.h>:

#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("%" PRIuPTR "\n", (uintptr_t) &argc);
}
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • which version of `C` this `PRIuPTR` is introduced? – IrAM Jan 18 '21 at 02:27
  • @IrAM: Last millennium, C 1999. – Eric Postpischil Jan 18 '21 at 03:01
  • Ohh, I came to know about it very recently!!! Does `uintptr_t` give correct values for pointers depends on platform, making it a portable solution? – IrAM Jan 18 '21 at 05:33
  • @IrAM: What are “correct values”? It is pretty portable. It is optional for an implementation to provide `uintptr_t`, but most C implementations do, and, if they do, the resulting `uintptr_t` value contains all the information needed to represent the pointer. How it is encoded as an unsigned integer is implementation-defined, so that aspect is not portable. Implementations with flat address spaces generally use the address directly for the integer value. Printing it in decimal is somewhat uncommon. Addresses are more often printed in hexadecimal, which you can do with `PRIxPTR`. – Eric Postpischil Jan 18 '21 at 19:38
3

Cast the pointer to uintmax_t (defined in <stdint.h>), and print the cast result with %ju:

printf("Printing p: %%p = %p, %%ju = %ju\n", p, (uintmax_t)p);

Note that there is no guarantee that uintmax_t is wide enough to hold a pointer, but it's probably OK. (If it's not OK for your platform, the compiler might complain.) You could use uintptr_t, as suggested elsewhere, but in the case that uintmax_t isn't wide enough, uintptr_t won't exist at all.

On the whole, you're better off learning how to deal with hexadecimal output :-)

Intrastellar Explorer
  • 3,005
  • 9
  • 52
  • 119
rici
  • 234,347
  • 28
  • 237
  • 341