您使用的是 64 位编译吗?
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()
上面代码中的第一个调用将一个 4 字节int
值和一个 8 字节int *
值压入堆栈,并告诉printf()
打印两个 4 字节数量。这些显然是int
8 字节地址的 4 字节和 4 字节。第二个printf()
调用将一个 8 字节int *
和一个 4 字节int
压入堆栈,并告诉printf()
再次打印两个 4 字节数量。不过,这一次,它们是分别int *
打印的 8 字节值的两半。这是严格调用未定义的行为,但这是一种似是而非的可能性,可以解释您看到的结果。
(有一些警告潜伏着。我假设对于 64 位编译,CHAR_BIT == 8
,sizeof(int) == 4
和sizeof(int *) == 8
; 并且实现传递堆栈上的参数,并且可能还有一些相关的假设,这些假设并没有被 C 标准严格保证,但是通常适用于 64 位编译器。)
你应该决定你要做什么。如果你想看4
两次,那么:
int number = 4;
int *pointer = &number;
printf("number = %d and pointer = %d\n", number, *pointer);
printf("pointer = %d and number = %d\n", *pointer, number);
如果你想查看地址,那么你应该使用%p
地址(并严格转换为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);
如果要控制指针的格式,则需要 C99#include <inttypes.h>
和:
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);
示例代码
#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;
}
带有警告的编译
Mac OS X 10.8.5 上的 GCC 4.8.1。也给出了类似的警告clang
。
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);
^
示例输出
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
有趣的是,系统设法4
在前两行输出中两次打印数字。我还没有研究过汇编器来看看它是如何工作的——但是调用“未定义行为”的好处之一是你不能抱怨结果;任何结果都是有效的,因为所需的行为是未定义的。