这是我正在尝试的代码。我无法理解我得到的输出。为什么在这里输出一些垃圾值而不是 10?
#include<stdio.h>
#include<string.h>
void f(int);
void (*foo)(float)=f;
int main()
{
foo(10);
return 0;
}
void f(int i)
{
printf("%d\n",i);
}
输出是一些垃圾值。
这是我正在尝试的代码。我无法理解我得到的输出。为什么在这里输出一些垃圾值而不是 10?
#include<stdio.h>
#include<string.h>
void f(int);
void (*foo)(float)=f;
int main()
{
foo(10);
return 0;
}
void f(int i)
{
printf("%d\n",i);
}
输出是一些垃圾值。
为什么输出一些垃圾
因为你对编译器撒谎。
你告诉它foo
是一个指向接受 a 的函数的指针,float
然后将它指向一个接受 a 的函数int
。
不要对编译器撒谎
这是未定义的行为。
您正在调用f
,这是一个接受 a 的函数int
,就好像它是一个接受 a 的函数一样float
。实际行为将取决于平台的调用约定如何工作 - 例如,如果int
和float
参数在同一个寄存器或同一个堆栈槽中传递,结果将是别名表示10.0f
为int
. 另一方面int
,如果float
以不同的方式传递,则结果将是适当的寄存器或堆栈槽中的任何垃圾。
此外,因为这是未定义的行为,编译器可以自由地做它喜欢的任何事情,如果启用了优化器,它可能会做。
在这种情况下,编译器通常会发出警告或错误,例如 GCC 说:
program.c:4: warning: initialization from incompatible pointer type
英特尔 C 编译器更详细:
program.c(4): warning #144: a value of type "void (*)(int)" cannot be used to initialize an entity of type "void (*)(float)"
void (*foo)(float)=f;
^
除了可能将参数值转换10
为浮点之外,如果您在 64 位机器上运行,还有另一个选项 - 调用约定。整数参数通过常规整数 CPU 寄存器(RDI
、RSI
等)传递,而浮点参数通过 SSE 寄存器(XMM0
、XMM1
等)传递。即使浮点值以某种方式与整数 1 兼容,被调用的函数也会在不同的寄存器 ( XMM0
) 中接收其参数,而不是它会查询值 ( RDI
) 的寄存器。
在 32 位机器上,整数和浮点参数都在堆栈上传递。你最终得到的是1092616192
IEEE 10.0
754 单精度浮点表示:
1092616192 = 0|10000010|01000000000000000000000
| | |
| | +---> significand = 1 + 2^(-2) = 1.25
| |
| +------------> exponent = 130 - 127 = +3
|
+--------------> sign = 0 (positive)
1.25 * 2^3 = 1.25 * 8 = 10.0
因为未定义的行为。
调用 throughfoo()
将整数转换10
为float
,然后将其解释为int
by f()
。
我很确定这不是很好定义的。
因为原型不同。编译器将“10”视为浮点数,并使用其浮点表示来调用f()
,而后者又将其视为整数,其二进制表示不具有值“10”。