C float*和int*的printf行为不同?
首先,让我澄清一下,我知道将指针作为参数传递给这些C float*和int*的printf行为不同?,c,printf,format-specifiers,C,Printf,Format Specifiers,首先,让我澄清一下,我知道将指针作为参数传递给这些printf说明符是不正确的。然而,我很想知道printf完成后会发生什么 使用正常的打印说明符,%d用于int,而%f用于float,为什么打印的是int*,而float*不会打印 例如,给定这些变量(单位化): 当这样称呼时: void printVar(int *a, float *b) { printf("%d\n", a);//why does "a" print at all? printf("%d %p\n",
printf
说明符是不正确的。然而,我很想知道printf
完成后会发生什么
使用正常的打印说明符,%d
用于int
,而%f
用于float
,为什么打印的是int*
,而float*
不会打印
例如,给定这些变量(单位化):
当这样称呼时:
void printVar(int *a, float *b)
{
printf("%d\n", a);//why does "a" print at all?
printf("%d %p\n", a, b);// when "b" prints only using %p
//printf("%d %f", a, b);// but fails on parameter mismatch using %f
printf("%d %f\n" , *a, *b);// prints normally (as expected)
}
为什么会出现这种情况?:(“a”可以打印,但“b”只能使用%p或通过*b打印)
[编辑]澄清和解决一些评论问题的完整代码:
#include <ansi_c.h>
void printVar(int *a, float *b)
{
printf("%d\n", a);//why does "a" print at all?
printf("%d %p\n", a, b);// when "b" prints only using %p
//printf("%d %f", a, b);// but fails on parameter mismatch using %f
printf("%d %f\n" , *a, *b);// prints normally (as expected)
}
int main()
{
int a, *pA;
float b, *pB;
char s[100], *pS;
pA = &a;
pB = &b;
pS = &s[0];
printVar(pA, pB);
getchar();
return 0;
}
#包括
void printVar(int*a,float*b)
{
printf(“%d\n”,a);//为什么“a”会打印?
printf(“%d%p\n”,a,b);//当“b”仅使用%p打印时
//printf(“%d%f”,a,b);//但使用%f时参数不匹配失败
printf(“%d%f\n”,*a,*b);//正常打印(如预期)
}
int main()
{
INTA,*pA;
浮动b,*pB;
字符s[100],*pS;
pA=&a;
pB=&b;
pS=&s[0];
printVar(pA,pB);
getchar();
返回0;
}
***[编辑2]如果取消对第三次打印的注释,则处理有关实际内容的一些注释F
我得到以下两个运行时通知,然后在第3行中没有得到printf的输出:让我们逐行检查代码
void printVar(int *a, float *b, char *s)
{
printf("%d\n", a); // here, printf print address of a as an int
printf("%d %p\n", a, b); // address of b is not a float number
printf("%d %f\n" , *a, *b);// *a is a int, *b is a float number
}
因为
b
不是浮点数,所以只有*b
是浮点数。指针实际上是整数(它们可能不是!),因此使用%d
说明符打印它们是可行的(并且结果不是很有意义)。您的程序的这种修改行为可能会很有启发性
#include <stdio.h>
void printVar(int *a, float *b)
{
printf("%d %e %p\n", a, a, a);
printf("%d %e %p\n", b, b, b);
printf("%d %e %p\n", *a, *a, *a);
printf("%d %e %p\n", *b, *b, *b);
}
int
main(void)
{
int a = 0x44444444;
float b = 5.019220152e+33;
printVar(&a, &b);
return 0;
}
#包括
void printVar(int*a,float*b)
{
printf(“%d%e%p\n”,a,a,a);
printf(“%d%e%p\n”,b,b,b);
printf(“%d%e%p\n”、*a、*a、*a);
printf(“%d%e%p\n”、*b、*b、*b);
}
int
主(空)
{
INTA=0x4444;
浮点数b=5.019220152e+33;
printVar(&a和&b);
返回0;
}
您有以下参数:
int *a, float *b
这:
很可能将a
(类型为int*
)占用的内存空间视为int
类型的对象。在许多系统上,这将给您带来几乎有意义的结果。(当然,如果确实要打印指针值,则需要将其强制转换为void*
并使用%p
,但您要问的是错误代码的行为,而不是如何修复它。)
如果int
和int*
的大小不一样,或者int
s和指针作为参数传递的方式不同(例如,一些CPU有专用地址和/或浮点寄存器),事情可能会变得奇怪
很可能void*
和float*
具有相同的表示形式,尽管该语言不能保证这一点。如果int
和int*
恰好大小相同,并且使用相同的参数传递约定传递,则很可能会将指针a
的内容打印为int
对象,然后将b
的值打印为指针
//printf("%d %f", a, b);// but fails on parameter mismatch using %f
“%f”
需要类型为double
的参数,而不是类型为float
(float
参数对于printf
等可变函数提升为double
)。如果int
和int*
的大小相同,double
和float*
的大小相同,并且所有这些类型都使用相同的参数传递约定进行传递,那么这很可能会打印指针对象a
的值,就像它是int
一样,指针对象b
的值,就好像它是一个double
对象一样。后者可能会给你一个完全是垃圾的浮点值,甚至可能是NaN或无穷大。但是,如果这些假设中的任何一个失败,printf
很可能会以与参数值匹配或不匹配的顺序从堆栈(或寄存器)中获取数据
上面的每一个printf
调用都有未定义的行为,这意味着,严格来说,您不应该对将发生的事情抱有任何期望——即使行为在任何方面都是一致的。了解封面下发生了什么有助于识别错误的原因(啊,垃圾浮点值看起来与我上个月弄乱格式字符串时得到的值相似),但实际上不适用于其他任何情况
printf("%d %f\n" , *a, *b);// prints normally (as expected)
啊,这更像是——但是如果这是在前面的调用之后执行的,它们未定义的行为可能会把事情搞得一团糟,甚至无法工作。另外,查看整个程序,main
中的变量a
和b
(其地址被传递到printVar
)没有初始化,因此即使在最好的情况下*a
和*b
也是垃圾。感谢haccks在评论中指出了这一点。这很简单——因为参数类型与格式字符串中的预期类型不匹配,所以会出现未定义的行为。任何事情都有可能发生,所以没有什么值得惊讶的
一些调用约定不在堆栈上传递浮点参数;相反,它们通过特殊的浮点寄存器传递,例如x87堆栈或SSE寄存器。因此,当printf
看到%f
格式说明符时,它尝试从这些位置读取浮点值,但当它看到%d
格式说明符时,它尝试从堆栈中读取整数。当您传入指针时,编译器会在堆栈上传递该指针
例如,这里有一个简单的函数:
void printVars(float a, float *p)
{
printf("%f\n", a);
printf("%p\n", p);
}
这是我的x86-64上的反汇编的注释版本
//printf("%d %f", a, b);// but fails on parameter mismatch using %f
printf("%d %f\n" , *a, *b);// prints normally (as expected)
void printVars(float a, float *p)
{
printf("%f\n", a);
printf("%p\n", p);
}
00000000004004f4 <printVars>:
;;; Function prologue
4004f4: 55 push %rbp
4004f5: 48 89 e5 mov %rsp,%rbp
4004f8: 48 83 ec 10 sub $0x10,%rsp
;;; Set up floating-point argument in %xmm0 register
4004fc: f3 0f 11 45 fc movss %xmm0,-0x4(%rbp)
400501: 48 89 7d f0 mov %rdi,-0x10(%rbp)
400505: f3 0f 10 45 fc movss -0x4(%rbp),%xmm0
40050a: 0f 5a c0 cvtps2pd %xmm0,%xmm0
;;; Set up format string argument (%rdi) and call printf
40050d: b8 3c 06 40 00 mov $0x40063c,%eax
400512: 48 89 c7 mov %rax,%rdi
400515: b8 01 00 00 00 mov $0x1,%eax
40051a: e8 d1 fe ff ff callq 4003f0 <printf@plt>
;;; Set up format string argument (%rdi) and pointer argument (%rsi) amd
;;; call printf
40051f: b8 40 06 40 00 mov $0x400640,%eax
400524: 48 8b 55 f0 mov -0x10(%rbp),%rdx
400528: 48 89 d6 mov %rdx,%rsi
40052b: 48 89 c7 mov %rax,%rdi
40052e: b8 00 00 00 00 mov $0x0,%eax
400533: e8 b8 fe ff ff callq 4003f0 <printf@plt>
;;; Function epilogue
400538: c9 leaveq
400539: c3 retq