以下代码打印99其中' c'被隐式转换为99。
printf("%d", 'c');
但以下代码打印0.000000:
printf("%f", 23);
为什么在第二种情况下整数23没有像第一种情况那样转换成23.00000?这是否反映了C中隐式转换的执行不佳?提前谢谢。
编辑:如果没有可能从int到float的提升作为答案之一,那么为什么在我们编写时会有一个int浮动的提升
float x = 23;
为什么会这样?
答案 0 :(得分:12)
在C中,'c' 是int
。没有进行转换。
即使它是char
(就像在C ++中一样),char
是一个整数类型,并且在printf
等可变函数的参数列表中,所有可变参数都经过算术推广,会自动将char
扩展为int
,或float
扩展为double
- 但不会int
扩展为{{1} }}
答案 1 :(得分:9)
printf
是一个可变函数,这意味着它的参数(除第一个之外)在被访问时实际上是无类型的。这排除了printf
的参数列表中的任何类型的智能类型转换(尽管有某些default conversions发生,盲目地且不管格式说明符。)
在第一个示例中,'c'已经是int
。但是在float的情况下,它没有执行将int
转换为float
所需的转换,因为编译器不知道它应该,或者更准确地说,根据规范,那里无所事事,但相信格式说明符是关于类型的真相来源。它认为数据已经是浮点数,因为格式说明符%f
正在告诉它,并且它无法看到传入的23的类型。
这使得开发人员很容易意外地导致崩溃 - 开发人员必须确保格式说明符(例如%d)与自己提供的数据相匹配。例如,将“%s”说明符与int
输入混合会导致运行时崩溃,因为编译器只会“相信”格式说明符没有错误。更糟糕的是,尝试完全省略数据... printf("%f %f %f")
将导致它查找甚至不存在的参数,这些参数将崩溃。遗憾的是编译器必须接受并构建这个崩溃的代码。
如果您想更密切地看到这个难题,请va_list
/ va_start
/ va_stop
,printf
使用。了解这种机制允许我们遍历发送到printf
的数据,但是,类型信息丢失了。它是无类型的二进制数据,并且要使用它,它使用格式说明符%f
来实现浮点数就在那里。然后它将二进制数据解释为float
并在显示之前将其写入字符串。
另一个看待它的角度是编译器在其类型系统中忽略了%f
之类的字符串内容... %f
已编译但在运行该函数时仅在运行时应用。但是在运行时,所有类型信息都会丢失--C有一个类型系统,但它只是编译时间。基本上,像%f
和C类型系统这样的字符串数据是完全没有通信的外来概念。所以试着想象你的程序没有像%f
这样的字符串数据。编译器如何知道运行编译时int-> float转换?
同样,这仅适用于可变函数,而不适用于常规函数调用。普通函数调用表现出类似于大多数现代语言的类型处理。另一方面,变量函数对于C来说是唯一的。与void *
指针类似,它们应该被认为是危险的并且要小心使用。
编辑:
float x = 23;
导致促销,因为该语言具有功能类型系统(尽管类型仅在编译时已知)。类型系统在可变参数函数内部不起作用,即printf
的输入。