下面的代码给出了Turbo C编译器中没有错误的输出,并给出了变量的地址及其值:
int a=5,*fp;
fp=&a;
printf("%d %d\n",fp,*fp);
但是当我使用GCC编译器在Linux中编译相同的代码时,它会出错:
`warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d %d\n",fp,*fp);`
但使用%p
格式说明符的相同代码在GCC编译器中有效,我同意。问题是:它是如何在Turbo C平台上运行的?
P.S。问题不在于(在Turbo C中)没有报告错误,而是在Turbo C上报告错误 它给出一个有符号整数值,该值在重复执行程序时不变;它可以是垃圾吗?
P.P.S Turbo C在64位Linux上运行在MSDOS平台和GCC上,如果有帮助的话。
答案 0 :(得分:2)
printf()
假设您将为signed int
说明符传递%d
。
在您使用的平台和编译器上,整数和指针的大小可能相同,printf()
能够正确显示它。您的指针被重新解释为int。
在另一个平台上编译和运行它,例如,int是32位而指针是64位(例如x64上的gcc)将是未定义的行为。如果你足够幸运,它会崩溃。如果没有,你会得到垃圾。
答案 1 :(得分:1)
%d
转换说明符要求相应的参数具有类型[signed
] int
。如果相应的参数实际上具有不同的类型,则行为显式未定义。无论预期类型和实际类型的相对大小如何,无论这些类型之间是否存在隐式或显式转换,都是如此。
当程序显示未定义的行为时,既不定义编译器的行为也不定义任何结果编译程序的任何部分的行为。 Turbo C不需要诊断问题。另一方面,gcc被允许诊断它,甚至拒绝错误的源代码,而不仅仅是警告你。就C而言,如果触发任何未定义的行为,整个程序的行为绝对是任何事情 - 从作者的意图(无论可能是什么)到发出粗鲁的评论来自机器的发言人,远远超出。
实际上,如果预期和实际类型的大小相同,且转换说明符不是%s
,则未定义的行为很可能(但绝不是确定的)以相对良性的方式显示。否则,所有赌注都会被取消。特别要注意的是,64位平台的许多C实现都具有32位int
和64位指针。
答案 2 :(得分:1)
每个转换说明符(例如%d
)都指定所需参数的类型和用于打印它的格式。
%d
需要int
类型的参数(等效signed int
),并以十进制格式打印。%u
需要unsigned int
类型的参数,并以十进制格式打印。%x
需要unsigned int
类型的参数,并以十六进制格式打印。等等。
在您的代码中:
int a=5,*fp;
fp=&a;
printf("%d %d\n",fp,*fp);
第二个%d
是正确的,因为相应的参数*fp
的类型为int
。但第一个是不正确的,因为相应的参数fp
的类型为int*
。
如果为转换说明符传递了错误类型的参数,则行为未定义。如果您这样做,编译器不需要警告您,因为在最常见的情况下无法检测错误(格式字符串不必是字符串文字)。一些编译器,包括gcc,将分析格式字符串,如果它们是字符串文字并警告不匹配。 Turbo C显然没有(这并不奇怪,它是一个非常古老的编译器)。
打印指针值的正确格式为%p
。这需要类型为void*
的参数,并以实现定义的方式打印它。应转换除void*
以外的类型的指针。
您的代码的正确版本是:
int a = 5, *fp;
fp = &a;
printf("%p %d\n", (void*)fp, *fp);
答案 3 :(得分:0)
这是一个警告,而不是错误。第一个编译器也可以说相同,但不是。
警告不会停止编辑,因此它也会起作用。他们只是不同的编译器。此外,编译器接受您的程序并不意味着该程序是正确的。