The C standard (ISO/IEC 9899:2011) has this to say about converting between pointers and integers:
6.3 Conversions
6.3.2.3 Pointers
¶5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.67)
¶6 Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.
67) The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to
be consistent with the addressing structure of the execution environment.
Note that the behaviour of converting between pointers and integers is implementation defined, not undefined. However, unless the integer type used is uintptr_t
or intptr_t
(from <stdint.h>
— or <inttypes.h>
), you are likely to see truncation effects if the sizes of the pointer and the integer types do not match. If you move your code between 32-bit and 64-bit systems, you will run into problems somewhere.
In your code, you have 64-bit pointers (because you're on Mac OS X 10.10 and you need to specify explicitly -m32
to get a 32-bit build, but your results are consistent with a 64-bit build anyway). When you pass those pointers to printf()
with the %d
and %x
conversion specifications, you are requesting printf()
to print a 32-bit quantity, so it formats 32 of the 64 bits you passed. The behaviour is ill-defined; you aren't getting a conversion, per se, but the calling code (in main()
) pushes a 64-bit pointer onto the stack and the called code (printf()
) reads a 32-bit quantity off the stack. If you requested that a single call to printf()
should print several values (e.g. printf("%d %x\n", p, p);
), you'd get more surprising results.
You should compile with options like:
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Werror …
With those options, your code would not compile; the compiler would complain about mismatches between the format strings and the values passed. When I saved your code into a file noise.c
and compiled it with clang
(from XCode 7.2, running on Mac OS X 10.10.5), I got:
$ /usr/bin/clang -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
> -Wold-style-definition -Werror noise.c -o noise
noise.c:5:20: error: format specifies type 'char *' but the argument has type 'char (*)[13]'
[-Werror,-Wformat]
printf("%s\n", &my_string);
~~ ^~~~~~~~~~
noise.c:7:20: error: format specifies type 'int' but the argument has type 'char (*)[13]' [-Werror,-Wformat]
printf("%d\n", &my_string);
~~ ^~~~~~~~~~
noise.c:8:20: error: format specifies type 'unsigned int' but the argument has type 'char (*)[13]'
[-Werror,-Wformat]
printf("%x\n", &my_string);
~~ ^~~~~~~~~~
noise.c:14:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
printf("%d\n", p);
~~ ^
%s
noise.c:17:11: error: incompatible integer to pointer conversion initializing 'char *' with an expression of
type 'int' [-Werror,-Wint-conversion]
char *p2 = 'p';
^ ~~~
noise.c:18:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
printf("%c\n", p2);
~~ ^~
%s
noise.c:20:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
printf("%d\n", p2);
~~ ^~
%s
7 errors generated.
$
Compile with stringent warnings, and pay heed to those warnings.