为什么在C中打印变量会改变它们的值?

时间:2013-10-04 04:11:05

标签: c pointers

我只是在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

那么,为什么价值只会随着印刷方向的变化而变化。我无法证明这一规则的合理性。

4 个答案:

答案 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 == 8sizeof(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)之间存在不匹配。