为什么printf打印的值与上面的值相同? int mainvoid { INTA=65; char c=chara; printf%c\n,c;//输出:A printf%f\n,floata;//输出:65.000000 printf%f\n,5/2;//输出:65.000000为什么??? 返回0; } //为什么打印%f\n,5/2;打印与上述数字相同的数字????

为什么printf打印的值与上面的值相同? int mainvoid { INTA=65; char c=chara; printf%c\n,c;//输出:A printf%f\n,floata;//输出:65.000000 printf%f\n,5/2;//输出:65.000000为什么??? 返回0; } //为什么打印%f\n,5/2;打印与上述数字相同的数字????,c,printf,C,Printf,它应该打印2.5,我想知道为什么它不打印这个数字,bts发生了什么? 我试图在谷歌上找到答案,但我不确定如何质疑这个问题,因为代码中有UB。在第三个printf中,传递整数,但printf需要double-UB 投下它,它就会正常工作 代码中有UB。在第三个printf中,传递整数,但printf需要double-UB 投下它,它就会正常工作 5和2是整数,5/2也是整数,并被截断为下一个整数,即2 试着投双打5/2 或者使用5.0/2.0,5和2是整数,5/2也是整数,并被截断为下一个整数,即

它应该打印2.5,我想知道为什么它不打印这个数字,bts发生了什么?
我试图在谷歌上找到答案,但我不确定如何质疑这个问题,因为代码中有UB。在第三个printf中,传递整数,但printf需要double-UB

投下它,它就会正常工作

代码中有UB。在第三个printf中,传递整数,但printf需要double-UB

投下它,它就会正常工作
5和2是整数,5/2也是整数,并被截断为下一个整数,即2

试着投双打5/2


或者使用5.0/2.0,5和2是整数,5/2也是整数,并被截断为下一个整数,即2

试着投双打5/2

或者使用5.0/2.0

C编译器将5/2计算为整数:5/2->2。 ptinf应为%f。 在您的计算机/os/compiler/libc上,从int[2]到float[?]的错误转换为30.00000,这是printf忠实地打印的。 为了证明这一点,我们可以使用更大的数字,例如5000/3。您应该正确地强制转换数据,或者使用正确的文本5.0而不是5

包括 int mainvoid { printf5/3 d:\t\t\t%d\n,5/3; //printf5/3 n:\t\t\t%n\n,5/3;//segfault 打印F5/3 f:\t\t\t%f\n,5/3; 打印双5/3 d:\t\t%d\n,双5/3; //printfdouble 5/3 n:\t\t%n\n,双5/3;//内存损坏 打印双5/3 f:\t\t%f\n,双5/3; printfloat 5/3 d:\t\t%d\n,浮动5/3; //printfloat 5/3 n:\t\t%n\n,float 5/3;//内存损坏 printffloat 5/3 f:\t\t%f\n,float 5/3; printf5/3 d:\t\t\t%d\n,5000/3; //printf5/3 n:\t\t\t%n\n,5000/3;//segfault 打印F5/3 f:\t\t\t%f\n,5000/3; 打印F5./3.d:\t\t%d\n,5./3。; //printf5./3.n:\t\t%n\n,5./3;//内存损坏 打印F5./3.f:\t\t%f\n,5./3。; 返回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,希望您会得到一个segfault,如果您运气不好,您将得到内存损坏和难以跟踪的bug

C编译器将5/2计算为整数:5/2->2。 ptinf应为%f。 在您的计算机/os/compiler/libc上,从int[2]到float[?]的错误转换为30.00000,这是printf忠实地打印的。 为了证明这一点,我们可以使用更大的数字,例如5000/3。您应该正确地强制转换数据,或者使用正确的文本5.0而不是5

包括 int mainvoid { printf5/3 d:\t\t\t%d\n,5/3; //printf5/3 n:\t\t\t%n\n,5/3;//segfault 打印F5/3 f:\t\t\t%f\n,5/3; 打印双5/3 d:\t\t%d\n,双5/3; //printfdouble 5/3 n:\t\t%n\n,双5/3;//内存损坏 打印双5/3 f:\t\t%f\n,双5/3; printfloat 5/3 d:\t\t%d\n,浮动5/3; //printfloat 5/3 n:\t\t%n\n,float 5/3;//内存损坏 printffloat 5/3 f:\t\t%f\n,float 5/3; printf5/3 d:\t\t\t%d\n,5000/3; //printf5/3 n:\t\t\t%n\n,5000/3;//segfault 打印F5/3 f:\t\t\t%f\n,5000/3; 打印F5./3.d:\t\t%d\n,5./3。; //printf5./3.n:\t\t%n\n,5./3;//内存损坏 打印F5./3.f:\t\t%f\n,5./3。; 返回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,希望您会得到一个segfault,如果您运气不好,您会得到内存损坏和难以跟踪的bug。

这是一个简化的答案,不一定完全准确,但是:在printf format语句中使用%f时,并不意味着接受传递的下一个参数,并将其作为浮点打印。不,它的意思是获取传递的下一个float参数,并打印它。但是在第三个printf调用中,没有传递浮点参数,因为5/2给出int值2。因此,当printf查找传递浮点参数的位置时,它偶然地获取了您传递的最后一个实际浮点数,即使它是由上一个printf调用传递的

这不一定会发生,显然这不是你想要依赖的那种东西,但它解释了为什么你看到了你所看到的

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

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

如果您的编译器不知道如何打印这样的警告,您可能希望尝试找到更好的警告。

这是一个简化的答案,但不一定完全准确,但是:在printf format语句中使用%f时,并不意味着接受传递的下一个参数,并将其作为浮点打印。不,它的意思是获取传递的下一个float参数,并打印它。但是在第三个printf调用中,没有传递浮点参数,因为5/2给出int值2。因此,当printf查找传递浮点参数的位置时,它偶然地获取了您传递的最后一个实际浮点数,即使它是由上一个printf调用传递的

这不一定会发生,显然这不是你想要依赖的那种东西,但它解释了为什么你看到了你所看到的

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

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

如果您的编译器不知道如何打印这样的警告,您可能希望找到更好的警告。

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

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

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

在您的情况下,行printf%f\n,floata;由于类型转换,将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.1和xxm1=12.2。由于第二个printf中的所有参数的计算结果都是整数,因此在xxm*寄存器中不会存储任何内容,这也意味着xxm*寄存器的旧值保持不变。因为%f期望实数在xxm*寄存器中,所以它只打印它们所持有的任何值(在本例中为第一个printf语句中的值)


您可以使用查看生成的汇编代码。

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

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

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

在您的情况下,行printf%f\n,floata;由于类型转换,将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.1和xxm1=12.2。由于第二个printf中的所有参数的计算结果都是整数,因此在xxm*寄存器中不会存储任何内容,这也意味着xxm*寄存器的旧值保持不变。因为%f期望实数在xxm*寄存器中,所以它只打印它们所持有的任何值(在本例中为第一个printf语句中的值)


您可以使用查看生成的汇编代码。

您使用什么编译器/平台?我得到了不同的结果。5/2是int,而不是double,这是printf使用%f说明符所期望的。简言之,当你说我要给你发一张双人支票时,你是在骗printf。我使用记事本++和gccprintf%c\n,c;/输出:根据C117.21.6.1p9,A@BartFriederichs,如果发送的格式说明符与参数类型不匹配,则调用UB。您使用什么编译器/平台?我得到了不同的结果。5/2是int,而不是double,这是printf使用%f说明符所期望的。简言之,当你说我要给你发一张双人支票时,你是在骗printf。我使用记事本++和gccprintf%c\n,c;/输出:每C117.21.6.1p一个@BartFriederichs
9,如果将格式说明符不匹配发送到参数类型,则调用UB。好的,我知道如何修复该问题,但我仍然不知道为什么它会精确地使用上面的数字?@Rebel请查看用户P_uj_uu的答案并打开链接,然后从上次printf中删除double并查看assemblerok中的更改,我知道如何修复该问题,但我还是不明白为什么上面的数字更准确?@Rebel查看用户P_uuj_uu的答案并打开链接,然后从上次打印中删除double并查看AssemblerOh中的更改,好的,谢谢。顺便说一句,在我的课程中,我们正在使用这个编译器,所以我无法更改,但感谢您现在向我解释清楚。哦,好的,谢谢。顺便说一句,在我的课程中,我们正在使用这个编译器,所以我不能更改,但感谢您现在向我说明这一点。