Are you using a 64-bit compilation?
int number = 4;
int *pointer = &number;
printf("number = %d and pointer = %d\n", number, pointer);
printf("pointer = %d and number = %d\n", pointer, number);
If so, the first printf()
call in the code above pushes a 4-byte int
value and an 8-byte int *
value onto the stack, and tells printf()
to print two 4-byte quantities. These are apparently the 4-byte int
and 4 bytes of the 8-byte address. The second printf()
call pushes an 8-byte int *
and a 4-byte int
onto the stack, and tells printf()
to print two 4-byte quantities again. This time, though, they are the two halves of the 8-byte int *
value printed separately. This is strictly invoking undefined behaviour, but it is one plausible possibility and would explain the result you saw.
(There are some caveats lurking around. I'm assuming that for a 64-bit compilation, CHAR_BIT == 8
, sizeof(int) == 4
, and sizeof(int *) == 8
; also that the implementation passes arguments on the stack, and possibly some related assumptions that are not strictly guaranteed by the C standard but that do typically apply to 64-bit compilers.)
You should decide what you're trying to do. If you want to see 4
twice, then:
int number = 4;
int *pointer = &number;
printf("number = %d and pointer = %d\n", number, *pointer);
printf("pointer = %d and number = %d\n", *pointer, number);
If you want to see the address, then you should use %p
for the address (and strictly cast to void *
):
int number = 4;
int *pointer = &number;
printf("number = %d and pointer = %p\n", number, (void *)pointer);
printf("pointer = %p and number = %d\n", (void *)pointer, number);
If you want to control the format for the pointer, then you need C99 #include <inttypes.h>
and:
int number = 4;
int *pointer = &number;
printf("number = %d and pointer = 0x%.16" PRIXPTR "\n", number, (uintptr_t)pointer);
printf("pointer = 0x%.16" PRIXPTR " and number = %d\n", (uintptr_t)pointer, number);
Example code
#include <stdio.h>
#include <inttypes.h>
int main(void)
{
int number = 4;
int *pointer = &number;
printf("number = %d and pointer = %d\n", number, pointer);
printf("pointer = %d and number = %d\n", pointer, number);
printf("number = %d and pointer = %d\n", number, *pointer);
printf("pointer = %d and number = %d\n", *pointer, number);
printf("number = %d and pointer = %p\n", number, (void *)pointer);
printf("pointer = %p and number = %d\n", (void *)pointer, number);
printf("number = %d and pointer = 0x%.16" PRIXPTR "\n", number, (uintptr_t)pointer);
printf("pointer = 0x%.16" PRIXPTR " and number = %d\n", (uintptr_t)pointer, number);
return 0;
}
Compilation with warnings
GCC 4.8.1 on Mac OS X 10.8.5. Similar warnings are given by clang
too.
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition it.c -o it
it.c: In function ‘main’:
it.c:8:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘int *’ [-Wformat=]
printf("number = %d and pointer = %d\n", number, pointer);
^
it.c:9:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("pointer = %d and number = %d\n", pointer, number);
^
Example output
number = 4 and pointer = 1417245952
pointer = 1417245952 and number = 4
number = 4 and pointer = 4
pointer = 4 and number = 4
number = 4 and pointer = 0x7fff54797500
pointer = 0x7fff54797500 and number = 4
number = 4 and pointer = 0x00007FFF54797500
pointer = 0x00007FFF54797500 and number = 4
Interestingly, the system manages to print 4
for the number both times in the first two lines of output. I've not studied the assembler to see how that works — but one of the beauties of invoking 'undefined behaviour' is that you cannot complain about the results; any result is valid precisely because the required behaviour is undefined.