尝试打印指针时 Turbo C 和 gcc 中 printf() 的不同行为
Different behavior of printf() in Turbo C and gcc when trying to print a pointer
下面的代码给出了在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 在 MSDOS 平台上是 运行,在 64 位平台上是 GCC Linux,如果有帮助的话。
这是警告,不是错误。第一个编译器也可以这么说,但没有。
警告不会停止编译,所以它也会起作用。它们只是不同的编译器。此外,编译器接受您的程序并不意味着该程序是正确的。
printf()
假定您将为 %d
说明符传递 signed int
。
在您使用的平台和编译器上,整数和指针可能大小相同,printf()
能够正确显示。您的指针被重新解释为 int。
在不同的平台上编译和 运行 这将是未定义的行为,例如,int 是 32 位的,指针是 64 位的(例如 x64 上的 gcc)。如果你足够幸运,它会崩溃。否则,你会得到垃圾。
%d
转换说明符要求相应的参数具有类型 [signed
] int
。如果相应的参数实际上具有不同的类型,则该行为是明确未定义的。无论预期类型和实际类型的相对大小如何,也无论这些类型之间是否可以进行隐式或显式转换,情况都是如此。
当程序表现出未定义的行为时,编译器的行为和任何生成的已编译程序的任何部分的行为都未定义。诊断问题不需要 Turbo C。另一方面,gcc 可以对其进行诊断,甚至可以拒绝带有错误的源代码,而不仅仅是通过警告来提醒您。就 C 而言,如果触发任何未定义的行为,整个程序的 行为绝对可以是任何行为——从作者的意图(无论可能是什么)到发出粗鲁的评论机器的喇叭,而且远远超出。
实际上,如果预期类型和实际类型大小相同,并且转换说明符不是 %s
,则未定义行为很可能(但绝不一定)以相对良性的方式表现出来。否则,所有赌注都将取消。请特别注意,许多 64 位平台的 C 实现具有 32 位 int
s 和 64 位指针。
每个转换说明符,例如 %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);
下面的代码给出了在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 在 MSDOS 平台上是 运行,在 64 位平台上是 GCC Linux,如果有帮助的话。
这是警告,不是错误。第一个编译器也可以这么说,但没有。
警告不会停止编译,所以它也会起作用。它们只是不同的编译器。此外,编译器接受您的程序并不意味着该程序是正确的。
printf()
假定您将为 %d
说明符传递 signed int
。
在您使用的平台和编译器上,整数和指针可能大小相同,printf()
能够正确显示。您的指针被重新解释为 int。
在不同的平台上编译和 运行 这将是未定义的行为,例如,int 是 32 位的,指针是 64 位的(例如 x64 上的 gcc)。如果你足够幸运,它会崩溃。否则,你会得到垃圾。
%d
转换说明符要求相应的参数具有类型 [signed
] int
。如果相应的参数实际上具有不同的类型,则该行为是明确未定义的。无论预期类型和实际类型的相对大小如何,也无论这些类型之间是否可以进行隐式或显式转换,情况都是如此。
当程序表现出未定义的行为时,编译器的行为和任何生成的已编译程序的任何部分的行为都未定义。诊断问题不需要 Turbo C。另一方面,gcc 可以对其进行诊断,甚至可以拒绝带有错误的源代码,而不仅仅是通过警告来提醒您。就 C 而言,如果触发任何未定义的行为,整个程序的 行为绝对可以是任何行为——从作者的意图(无论可能是什么)到发出粗鲁的评论机器的喇叭,而且远远超出。
实际上,如果预期类型和实际类型大小相同,并且转换说明符不是 %s
,则未定义行为很可能(但绝不一定)以相对良性的方式表现出来。否则,所有赌注都将取消。请特别注意,许多 64 位平台的 C 实现具有 32 位 int
s 和 64 位指针。
每个转换说明符,例如 %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);