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