繁体   English   中英

为什么 printf 打印出与它上面的值相同的值?

[英]why printf prints same value as the value above it?

int main(void)
{
    int a = 65;
    char c = (char)a;

    printf("%c\n", c);              // output: A
    printf("%f\n", (float)a);       // output: 65.000000
    printf("%f\n", 5/2);            // output: 65.000000 why???


    return 0;
}
//why printf("%f\n", 5/2); prints same number as a number above????

它应该打印 2.5,我想知道为什么它不打印这个数字以及 bts 会发生什么? 我试图在谷歌上找到答案,但我不知道如何质疑这个问题

你在那个代码中有 UB。 在第三个 printf 中 - 你传递整数但 printf 期望双倍 - UB

投它,它会正常工作https://godbolt.org/z/M3ysha

这是一个简单而不一定是完全准确的答案,但是:当您使用%fprintf格式声明,这并不意味着“采取传递的一个参数,并将其打印为浮动”。 不,它的意思是“获取传递的下一个浮点参数,并打印它”。 但是,在你的第三个printf电话,这是没有通过float参数(因为5/2int值2)。 因此,当printf去查看传递浮点参数的地方时,它偶然地选择了您传递的最后一个实际浮点数,即使它是由前一个printf调用传递的。

这不能保证会发生,显然这不是你想要依赖的那种事情,但它解释了为什么你看到了你所看到的。

好的编译器会在printf参数的数量或类型与格式字符串不匹配时发出警告,从而帮助您避免这种错误。 例如,我的说

warning: format specifies type 'double' but the argument has type 'int'

如果您的编译器不知道如何打印这些警告,您可能想尝试找到一个更好的。

5 和 2 是整数,5/2 也是整数并被截断到下一个整数,即 2

尝试投(双)(5/2)

或使用 5.0 / 2.0

  • C 编译器将5 / 2计算为整数:5 / 2 -> 2。
  • ptinf()期待一个%f
  • 在您的机器/操作系统/编译器/libc 上从 int[2] 转换为 float[?] 的错误是 30.00000, printf忠实地打印出来。

为了证明这一点,我们可以使用更大的数字,例如 5000 / 3。 您应该正确地转换数据,或使用正确的文字 5.0 而不是 5。

#include <stdio.h>

int main(void)
{
  printf("5/3 d:\t\t\t %d\n", 5/3);
  // printf("5/3 n:\t\t\t %n\n", 5/3); // segfault
  printf("5/3 f:\t\t\t %f\n", 5/3);

  printf("(double) 5/3 d:\t\t %d \n", (double) 5/3);
  // printf("(double) 5/3 n:\t\t %n \n", (double) 5/3); // memory corruption
  printf("(double) 5/3 f:\t\t %f \n", (double) 5/3);

  printf("(float) 5/3 d:\t\t %d \n", (float) 5/3);
  // printf("(float) 5/3 n:\t\t %n \n", (float) 5/3); // memory corruption
  printf("(float) 5/3 f:\t\t %f \n", (float) 5/3);

  printf("5/3 d:\t\t\t %d \n", 5000/3);
  // printf("5/3 n:\t\t\t %n \n", 5000/3); // segfault
  printf("5/3 f:\t\t\t %f \n", 5000/3);

  printf("5./3. d:\t\t %d \n", 5./3.);
  // printf("5./3. n:\t\t %n \n", 5./3.); // memory corruption
  printf("5./3. f:\t\t %f \n", 5./3.);

  return 0;
}

输出:

5/3 d:           1
5/3 f:           0.000000
(double) 5/3 d:      33989216 
(double) 5/3 f:      1.666667 
(float) 5/3 d:       33989216 
(float) 5/3 f:       1.666667 
5/3 d:           1666 
5/3 f:           1.666667 
5./3. d:         33989216 
5./3. f:         1.666667 

所以,不管是 5/2 还是其他什么,重要的是数据类型。 在您的情况下,转换链: (float) (int) 5/2 = 1意外地等于 30.0000 float。

此外,将 2 或 4 个字节的整数输入 printf 并告诉它期望 8 个字节(例如传递 int 和格式化为 double),希望你会得到段错误,如果你足够不幸,你会得到内存损坏和困难跟踪错误。

这种行为是由于参数传递给函数的方式造成的。

例如,整数值通过 edx、esi 等寄存器传递(只要参数适合可用寄存器)。 但是,浮点参数在 xmm* 寄存器中传递(只要它们适合可用的寄存器)。

因此,在函数内部,根据类型说明符从适当的寄存器中获取值。 因此%d将从edx / esi等中获取,而%f将从xmm*寄存器中获取。

在您的情况下,该行printf("%f\\n", (float)a); 由于类型转换,将a的值(即 65)存储为实际值65.0 因此, xxm0寄存器的值为 65.0。

现在当控制来到printf("%f\\n", 5/2); ,函数参数5/2是一个整数。 所以它不会被推入xxm0寄存器。 但是,由于%f期望xxm* (在本例中为xxm0 )寄存器中的值,因此它只会重试 xxm0 中的任何值。 在您的情况下, xxm0已存储来自早期printf()调用的值 65.0 。 所以 65.0 被打印出来。

下面的程序应该更清楚:

int main(void)
{
    printf("%f\n", 10, 11.1, 12.2, 40);       // 11.100000
    printf("%f %f\n", 5/2, 1, 2, 3, 4);       // 11.100000 12.200000
}

在第一次printf()调用期间, xxm0 = 11.1xxm1 = 12.2 由于第二个printf()中的所有参数都计算为整数,因此xxm*寄存器中不会存储任何内容(这也意味着xxm*寄存器的旧值保持不变)。 由于%f期望实数在xxm*寄存器中,因此它只打印它们保存的任何值(在这种情况下,来自第一个printf()语句的值)。

您可以使用https://www.godbolt.org查看生成的汇编代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM