我只是在C中编写一个简单的程序,如下所示:
#include <stdio.h>
void main()
{
int *pointer;
int number = 4;
printf("number = %d\n",number);
pointer = &number;
printf("number = %d and pointer = %d\n",number,pointer);
printf("pointer = %d and number = %d",pointer,number);
}
然后执行它打印输出,如:
number = 4 and pointer = 8724
pointer = 8724 and number = 9415
那么,为什么价值只会随着印刷方向的变化而变化。我无法证明这一规则的合理性。
答案 0 :(得分:5)
您使用的是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 *
值推送到堆栈上,并告诉{{1}打印两个4字节的数量。这些显然是8字节地址的4字节printf()
和4字节。第二个int
调用将8字节printf()
和4字节int *
推入堆栈,并告诉int
再次打印两个4字节数量。但这一次,它们是分别打印的8字节printf()
值的两半。这是严格调用未定义的行为,但这是一种合理的可能性,并且可以解释您看到的结果。
(潜伏着一些警告。我假设这是64位编译,int *
,CHAR_BIT == 8
和sizeof(int) == 4
;也是实现通过堆栈上的参数,以及可能的一些相关假设,这些假设并非C标准严格保证,但通常适用于64位编译器。)
你应该决定你要做什么。如果您想要sizeof(int *) == 8
两次,那么:
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 *
如果你想控制指针的格式,那么你需要C99 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);
和:
#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);
Mac OS X 10.8.5上的GCC 4.8.1。 #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;
}
也提供了类似的警告。
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
这个数字。我没有研究汇编程序,看看它是如何工作的 - 但是调用'未定义行为'的一个好处就是你不能抱怨结果;任何结果都是有效的,因为所需的行为是未定义的。
答案 1 :(得分:2)
可能是由于未定义的行为!正在为地址传递错误的格式字符串。
使用%p
打印地址并将其指定为void*
。
printf("number = %d and pointer = %p\n",number, (void*)pointer);
printf("pointer = %p and number = %d", (void*)pointer, number);
printf
的部分引用的fprintf函数返回格式字符串段落:
如果转换规范无效,则行为未定义。[...]
来自@Shafik Yaghmour'answer
的文字答案 2 :(得分:1)
使用*pointer
代替pointer
。
Pointer
打印地址和*pointer
打印值。
printf("number = %d and pointer = %d\n",number, *pointer);
^
printf("pointer = %d and number = %d",*pointer,number);
^
答案 3 :(得分:1)
您似乎正在使用一个平台,其中int
的大小和指针的大小不同,或者参数传递的指针和整数可能不太可能。您尝试打印的类型(%d
)与传递的类型(第一种情况下的int /指针和第二种情况下的指针/ int)之间存在不匹配。