2

I am using the following piece of code as a learning exercise for pointers:

int a=8;

int *ptr=&a;

printf("\nThe & address of a is: %x\n",&a);
printf("\nThe value of the pointer ptr is: %p \n",ptr);

I am doing this to identify the address values given by &a and ptr and I am noticing the following difference in the output:

The & address of a is: a6bff9c4

The value of the pointer ptr is: 000000f5a6bff9c4

I can see that the ptr value is the & value with 000000f5 appended in the beginning. I know that %x outputs the & address value in hexadecimal. What is the format of the pointer value and how is it different from the hexadecimal & value?

Trying to understand the difference between the memory addresses outputted by & and pointer variable and understanding their formats.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
NeuronB
  • 53
  • 6
  • 9
    The first example is incorrect: `%x` is for type `unsigned int`. In this case your 64-bit pointer was truncated to 32 bits, but the behaviour is undefined. – Weather Vane May 08 '23 at 14:43
  • Format specifier `%p` requires an argument of type `void*`, not `int*`. There is no automatic conversion for variadic functions. You need to cast the value explicitely. – Gerhardh May 08 '23 at 14:46
  • To add to what @WeatherVane said, you can prevent that truncation if you use `%x` (for a long unsigned int), you'll see that the results are now the same (except for the `0x` prefix in the `%p`, but that's just a stylistic difference) – Alexander May 08 '23 at 14:46
  • 2
    @Alexander did you mean `%llx` for `unsigned long long`? It's still undefined behaviour though. – Weather Vane May 08 '23 at 14:54
  • @Alexander There is no `0x` prefix for both format specifiers. – Gerhardh May 08 '23 at 15:13
  • @Gerhardh I'm getting `The value of the pointer ptr is: 0x16d71b38c` on my machine (macOS 13.3). – Alexander May 08 '23 at 15:29
  • @Alexander interesting. I see that is implementation defined. In the output of the OP you can see that there is no `0x` – Gerhardh May 08 '23 at 15:47
  • Hi everyone, I now understand that the value is being modified according to the format provided. For %x, I am getting e25ffd04. For %llx, I am getting ee25ffd04. For %p, I am getting 0000000ee25ffd04 – NeuronB May 08 '23 at 17:18
  • Hi @Gerhardh, can you please help me understand by explaining a bit more why casting to (void *) is required? Because with or without casting the same output is displayed – NeuronB May 08 '23 at 17:53
  • 1
    Getting an expected result does not mean that you can rely on that. The C standard demands that the argument passed is of type `void *`. If you provide any other type (also any other pointer type) you cannot rely on that value having the same representation as a `void*` even if they point to the same address. If you have a function with `void*` in the parameter list and you provide a different pointer, the compiler will automatically convert it because that are the rules for `void*`. But as `printf` does ont have a type for its parameters, that automatic conversion is not possible. – Gerhardh May 08 '23 at 18:24

3 Answers3

4

Using the %x format specifier truncates part of the data you are attempting to display. %x is essentially designed to format an int in its hexadecimal form, typically with room for 4 bytes, but being asked to represent a pointer that in this case (but not always) occupies more space than an int

The %p format specifier is specifically designed to accommodate depictions of pointers. Depending on the addressing of the system the pointer is referencing, it will be either 4 bytes (32bit) or 8 bytes (64bit)

Thus a6bff9c4 is erroneously depicted with %x, and should be depicted using %p.

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • @NeuronB - Referring to your question regarding why cast "%p" arguments to void *, read [this](https://stackoverflow.com/questions/54598093/why-is-a-pointer-cast-as-voidp-when-used-in-printf/54598134#54598134), or [this](https://stackoverflow.com/a/11629682/645128), or [this](https://stackoverflow.com/questions/54598093/why-is-a-pointer-cast-as-voidp-when-used-in-printf/54598134#54598134). – ryyker May 08 '23 at 21:16
2

In your case, &a and ptr - they have same numerical value.

According to the specification, to print an address (either generated by using &variable, or stored in a pointer variable), always use %p format specifier, and cast the argument to (void *). Anything else, is undefined behaviour.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
2

The conversion specification %x expects an object of the type unsigned int. sizeof( unsigned int ) usually is equal to 4. While sizeof( int * ) is equal to 4 or 8 bytes depending on the used system.

Using invalid conversion specification results in undefined behavior.

From the C Standard (7.21.6.1 The fprintf function)

9 If a conversion specification is invalid, the behavior is undefined.275) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

Instead of this call where with a pointer there is used the conversion specification %x

printf("\nThe & address of a is: %x\n",&a);

you should write

#include <inttypes.h>

//...

printf("\nThe & address of a is: %08" PRIXPTR "\n", ( uintptr_t ) ( void * )&a);

you need to write

And in the second call of printf you need to convert the pointer to the type void *.

Here is a demonstration program.

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

int main( void )
{
    int a = 8; 

    int *ptr = &a;

    printf( "\nThe & address of a is: %08" PRIXPTR "\n", ( uintptr_t )( void * )&a );
    printf( "\nThe value of the pointer ptr is: %p \n", ( void * )ptr );
}

The program output might look like

he & address of a is: 0116F9BC

The value of the pointer ptr is: 0116F9BC

This call of printf

printf( "\nThe & address of a is: %08" PRIXPTR "\n", ( uintptr_t )( void * )&a );

can be more flexible if to rewrite it the following way

printf( "\nThe & address of a is: %0*" PRIXPTR "\n", 2 * ( int )( sizeof( &a ) ), ( uintptr_t )( void * )&a );
    
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335