using %x to print the hex address contained in a pointer

12,268

Solution 1

%x expects its corresponding argument to have type unsigned int, which is why you get the warning and funky output. Use %p to display pointer values:

T *p = some_pointer_value;
...
printf( "p = %p\n", (void *) p );

%p expects its corresponding argument to have type void *. This is pretty much the only place you should explicitly cast a pointer to void * in C.

Edit

Just looked at the page. Be aware, that code sample is old (written ca. 1990) and uses K&R-style (pre-1989 standard) function definition syntax and implicit int all over the place. It's using %x to display pointer values because the %p conversion specifier wasn't added to the language until the 1989 standard.

It should not be used as a model of modern C programming practice.

His explanation of pointers is pretty decent, though.

Solution 2

Pointers if manipulated with the intergral formats like %x or %u give undefined results. %p is recommended for pointers. As far as the warning is concerned, %x expects an unsigned int, and your variable has probably different size or alignment requirement than unsigned int so you are getting the warning.

Solution 3

%x is used to print a value in hex. While pointers are usually written in hex, there are other considerations for pointers that make %x a bad fit, like that 1C output you saw.

%p is meant for pointers, and is probably what you're looking for. It will format the pointer a bit better, since it knows that it's a pointer.

1C is a perfectly valid hex output, but it's odd for a pointer, since you expect certain special things to happen when displaying pointers, like having the correct length.

Since %x is meant for hex numbers, passing a pointer into it will give you a warning. One reason it gives you the warning is that pointers aren't necessarily the same size as an unsigned int.

Solution 4

Values cannot be "hex". Values are just values. Meanwhile, "hex" is a way to represent values for human consumption. "Hex" is a notation.

Using %x directly on pointers is illegal though, since %x format specifier expects an unsigned int argument, not a pointer. A pointer can be cast to unsigned int type, and the result can be used with %x format specifier, but this will not work in general case since unsigned int type can easily be too narrow to properly represent the numerical address value.

In other words, forget about %x. It is hopelessly useless in that application. The author of your article is doing it very wrongly.

If you really want to print a pointer p through its conversion to integral type, the proper way to go would be this

printf("%" PRIxPTR "\n", (uintptr_t) p);

Note the use of uintptr_t type and PRIxPTR macro that stands for an implementation-defined format specifier associated with that type.

Other than that you can use a dedicated format specifier %p, which prints void * pointers and typically uses hex notation for that purpose.

Solution 5

%x expects an unsigned int, passing anything else is UB.

For printing a data-pointer, there is %p which can print void-pointers (type void*, the conversion is not optional), which will normally print it with hexadecimal notation.

If that's not satisfying you, consider casting the pointer to uintptr_t and printing that using the format-specifier-macros PRIxPTR or PRIXPTR from <inttypes.h>, for guaranteed hexadecimal output.
You even get to select the case used.

Share:
12,268
user96454
Author by

user96454

Updated on June 04, 2022

Comments

  • user96454
    user96454 about 2 years

    i just read this short article http://karwin.blogspot.com/2012/11/c-pointers-explained-really.html which describes pointers really well. The author however says that the addresses are just these hex values, so he prints it with %x, but when i do this not only do i get a warning from the compiler saying i am passing a pointer instead of an unsigned int, but sometimes i get something that doesn't resemble an address at all (like 1C). Can somebody clarify the issue please?

    • Alexis
      Alexis almost 10 years
      use %p for pointer
    • Drew McGowen
      Drew McGowen almost 10 years
      I went ahead and commented on the post :P
    • Deduplicator
      Deduplicator almost 10 years
      @DrewMcGowen Actually, pointers could be smaller as well, for a different disastrous effect. Also, it is UB no matter the manner you lie to the compiler.
  • Keith Thompson
    Keith Thompson almost 10 years
    %x is used to print an unsigned int value in hex; passing anything else causes undefined behavior. Using %x with a pointer will not necessarily produce a warning, though some compilers (gcc, for example) will try to warn about it when they can. (That's not always possible, since the format string needn't be a string literal.)
  • Keith Thompson
    Keith Thompson almost 10 years
    To print a pointer value, use %p and cast the value to void*. %p is defined only for void*. There's no guarantee that other pointer types (apart from char* and friends) even have the same size or representation.
  • Deduplicator
    Deduplicator almost 10 years
    @KeithThompson: Added that conversion is required, thanks for reminding me.
  • Deduplicator
    Deduplicator almost 10 years
    %p is not for all pointers, only for pointers of type void*. Only data-pointers can be converted to it, unless the implementation guarantees it (a quite common extension even mentioned in the standard).
  • user96454
    user96454 almost 10 years
    this makes sense, but my pointer is int *, so the unsigned int type should suffice if we are considering byte size right? So then, in this particular case, why do i get these different outputs if both %x and %p are supposed output a hex value
  • user96454
    user96454 almost 10 years
    so %x didn't require an unsigned int then? And if it did, then my question remains: How come he is getting an output of the type 0x... which does look like an address, and i am only getting a small portion of the address if not a completely wrong value.
  • AnT stands with Russia
    AnT stands with Russia almost 10 years
    @user96454: I don't see how it has anything to do with the type of your pointer. The fact that your pointer is int * makes no difference whatsoever. In a typical implementation all pointers are represented in the same way. Which means that unsigned int might end up being insufficiently wide to represent pointers, any pointers.
  • AnT stands with Russia
    AnT stands with Russia almost 10 years
    What difference do you see in the output between %x and %p? If %p gives you longer output, it means that your pointers are indeed too large for unsigned int, which is why you get different (truncated) output from %x.
  • John Bode
    John Bode almost 10 years
    @user96454: if the type isn't what the conversion specifier expects, then the behavior is undefined; the exact output will vary.