使用 printf 使用 %d 打印浮点指针

SAN*_*KIE 2 c printf pointers

当我运行此代码时,它会打印第一个 printf 中 a 的地址,以及第二个 printf 中 a 的值。

#include <stdio.h>
int main() 
{
float a=7.999999;
float *b,*c;
b=&a;
c=b;
printf ( "\n%u %u %u", &a, b, c );
printf ("\n%f %f %f %f",a,*( &a ),*b,*c );
}
Run Code Online (Sandbox Code Playgroud)

但是当我像这样在第二个 printf 中将 %f 更改为 %d 时。

#include <stdio.h>   
int main() 
{
float a=7.999999;
float *b,*c;
b=&a;
c=b;
printf ( "\n%u %u %u", &a, b, c );
printf ("\n%d %d %d %d",a,*( &a ),*b,*c );
}
Run Code Online (Sandbox Code Playgroud)

它在第二个 printf 中打印随机值,请解释原因。浮点指针应该使用 %f 打印,但为什么不能使用 %d 打印。

Eri*_*hil 6

\n

为什么浮点指针应该使用 %f 打印,但为什么不能使用 %d 打印。

\n
\n

转换规范 (%d%f) 说明了printf两件事:

\n
    \n
  • 在哪里可以找到已通过的参数。
  • \n
  • 如何解释该论证的各个部分。
  • \n
\n

关于第一点,现代处理器通常对整数数据和浮点数据具有不同的寄存器。由于这个原因和相关原因,参数如何传递到子例程(计算环境的应用程序二进制接口的一部分)的规则通常规定前几个整数参数在某些整数寄存器中传递,前几个浮点参数在浮点寄存器中传递。(在前几个参数之后,通常会在硬件堆栈上传递其他参数。)

\n

因此,当您告诉printf使用转换数字%d但向其传递浮点参数时,printf可能会从某个整数寄存器中获取值,但浮点参数不存在。它在一些浮点寄存器中。然后printf打印错误的值。

\n

关于第二点,整数和浮点数的值以不同的位编码。%d告诉printf将这些位解释为二进制数(以及一些表示负数的方案,最常见的是两个\xe2\x80\x99s补码)。%f告诉printf将这些位解释为具有浮点格式的数字编码。另外,由于 C 的历史,float参数 被printf作为 传递double。最常见的浮点格式double使用 1 位表示符号,11 位表示 2 的指数,52 位表示尾数部分。(在普通科学记数法中,对于数字 \xe2\x88\x923.74\xe2\x80\xa210 13, \xe2\x88\x92 是符号,13 是指数,3.74 是有效数。printf)编码 adouble并根据 解释它们的部分或全部位%d,它会打印一个与浮点数的值非常不同的数字(除了极其罕见的巧合)。

\n

另请注意,没有打印或传入任何指针printf ("\\n%d %d %d %d",a,*( &a ),*b,*c );a*( &a )*b*c都是a

\n

在 中printf ( "\\n%u %u %u", &a, b, c );,指针打印不正确。正确的代码是printf("%p %p %p\\n", (void *) &a, (void *) b, (void *) c);. 这里我做了三处修改:

\n
    \n
  • %p是打印指针的正确转换规范。有时打印%u会打印相同的值(尽管是十进制而不是十六进制),但是,如果发生这种情况,那只是因为指针在与 相同的位置传递unsigned int,它们的大小相同,并且错误不会与编译器优化。
  • \n
  • 指针被强制转换void *为用于打印。%p这确保它们在通过时采用通用形式,适合。
  • \n
  • 我将 移到\\n了字符串的末尾而不是开头。C 设计为将换行符放在行尾而不是行首,因为当存在换行符时,它会立即将输出发送到交互设备,而不是将其保存在缓冲区中。
  • \n
\n