C语言中使用%d和%f进行printf输出

10

我在编写这个程序时发现,使用 %f 表示 double 类型和使用 %d 表示 float 类型得到的结果完全不同。 有谁知道为什么会出现这种情况吗?

int main ()
{
 float a = 1F;
 double b = 1;

 printf("float =%d\ndouble= %f", a, b);
}

这是输出结果

float = -1610612736
double = 190359837192766135921612671364749893774625551025007120912096639276776057269784974988808792093423962875123204096.0000

请参阅C11规范中的§7.21.6.1 printf函数(或POSIX规范中的fprintf())以了解如何正确使用printf(),以及关于浮点参数传递给可变参数函数的方式,请参阅§6.5.2.2 函数调用 ¶6和7。像GCC和Clang这样的现代C编译器可以提供广泛的格式不匹配诊断 - 您应该启用编译警告。 - Jonathan Leffler
4个回答

6

%d代表十进制,需要传入一个int类型的参数(或者一些较小的有符号整数类型会被提升)。浮点类型floatdouble以相同的方式传递(都会被提升为double),并且它们都使用%f。在C99中,您还可以使用%lf表示double的更大尺寸,但这纯粹是外观上的区别(请注意,使用scanf时不会进行提升,这实际上会产生差异)。


这是真的 http://codepad.org/labE8lgy 但我确实想知道它是如何工作的.. - Earlz

4
由于变量参数的工作方式,C语言除了 %d 和 %f 以外,并不知道你传递给它的是什么类型的值。当你传递一个变量参数时,实际上相当于 (void*)&myvalue,因为编译器和运行时函数都无法确定变量的类型,除非在格式化字符串中明确给出。所以即使有隐式转换可用,编译器也不知道需要它。
另外,大多数系统上双精度浮点数(double)占8个字节而单精度浮点数(float)占4个字节,这两种类型并不二进制兼容。这就像试图将一个字符串解释为双精度浮点数或其他不兼容的类型一样。

3
正确,但这不是关于floatdouble之间兼容性的问题。事实上,在传递之前,float类型的可变参数总是会被提升为double类型,意味着这里并没有涉及到float类型。传递给printf的两个值都具有double类型。第一个值内部被解释为一个int(因为它有 %d指示符)。intdouble之间的不兼容性是导致观察到的未定义行为的原因。 - AnT stands with Russia
对于可变参数函数(如 printf()),传递给变量参数列表的任何 float 值都会自动转换为 double(参见 C11 §6.5.2.2 函数调用 ¶6 & 7)。 - Jonathan Leffler
我真的无法同意“你基本上正在做(void *)&myvalue”——这些值是作为值传递的,而不是作为指针。 - Jonathan Leffler

3

这与数据的内部表示有关。您试图将一个浮点数打印成整数,但它具有完全不同的内部(二进制)表示。

double 的情况类似。在浮点变量后面可能有垃圾数据,这些垃圾数据会被解释为双精度浮点数的一部分。


1

%d 打印整数,所以你的 printf 将你的变量 a 解释为 int。

使用 gcc 3.4.6,在你的代码中我得到了两个值都是 0(在将 a 的初始化中的 F 去掉后,因为那会导致编译器错误)。我怀疑这与被解释为 int 的 a 变量的部分为 0 有关,然后编译器就混淆了……(可能有更好的解释,但我想不出来)。

对于两个变量,使用 %f 打印都会得到 1.000000。

你可以在此页面底部找到转换字符列表:

http://www.exforsys.com/tutorials/c-language/managing-input-and-output-operations-in-c.html


F 相关的编译器错误是因为它不能附加到整数上(例如,1.0F 是可以的)。 - RastaJedi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接