我只是想知道为什么当我尝试打印char
和整数值的加法时会得到一个 0 值。我的代码如下:
int y;
y = 10;
char z;
z = '9';
printf("%f", z + y);
这个 printf 的调用
printf("%f", z + y);
调用未定义的行为,因为您对 int 类型的对象使用了不正确的转换说明符%f
。
例如,您需要投射参数
printf( "%f", ( double )( z + y ) );
或
printf( "%f", ( float )( z + y ) );
尽管在最后一种情况下,由于默认参数升级,参数将被提升为双精度类型。
大多数情况下,当你调用一个函数,并且你传递了错误类型的参数时,C 会自动为你转换它。 例如,如果我写
#include <math.h>
int i = sqrt(144);
printf("%dn", i);
这有效,并打印12
. 即使sqrt
函数实际上想要一个double
类型的参数,它也可以工作——因为编译器知道这一点,并在将我的int
参数144
传递给sqrt
之前自动将其转换为double
。 (在返回的过程中还有一个转换,因为sqrt
返回一个double
,在分配给i
之前必须将其转换回int
。
但printf
函数本身就是这个规则的一个很大的例外。 在你的代码中,你有
printf("%f", z + y);
现在,你和我都知道%f
想要一个double
,但这不是传统上C语言可以知道的事情。 就 C 语言而言,printf
函数接受一个类型const char *
(即字符串)的参数,然后可能接受一些其他参数,具体取决于运行时在格式字符串中找到的特定%
序列。 因此,编译器只做了一个半心半意的尝试,将它们转换为几个常见的类型,然后将它们传递给printf
来完成其余的工作。 在你的例子中,由于z
是一个char
,y
是一个int
,z + y
将是一个int
,这就是传递给printf
的内容。 当printf
咀嚼格式字符串并找到格式说明符%f
时,它无法知道实际传递了哪种类型的参数,因此它甚至无法尝试进行自己的任何转换。 它所能做的就是假设你实际上通过了double
——而且,由于你没有,你会得到一个毫无意义的值。
现在,尽管正如我刚才所解释的,编译器传统上没有任何许可证来尝试将printf
参数转换为正确的类型,但现代编译器通常会查看格式字符串(如果可以的话),并检查事情在运行时是否正常工作。 例如,当我通过我的一个编译器运行您的代码时,我得到warning: format specifies type 'double' but the argument has type 'int'
. 如果您的编译器没有给您这样的警告,您可能想知道是否有办法启用它们,因为它们显然非常方便。
正如在注释部分中已经指出的那样,您有责任确保格式字符串和函数参数匹配。在您的情况下,它们不匹配。表达式z + y
的结果是int
类型,但您在格式字符串中使用了%f
转换说明符,该说明符仅对数据类型float
和double
有效(float
提升为double
)。
如评论部分所述,您有两种选择来解决此问题:
- 将格式字符串更改为需要类型为
int
的参数,或 - 将参数转换为
double
或float
使用选项 #1 的解决方案如下所示:
更改行
printf("%f", z + y);
自
printf("%d", z + y);
使用选项 #2 的解决方案如下所示:
更改行
printf("%f", z + y);
自
printf("%f", (double) (z + y) );