据我所知,在不兼容的函数指针之间进行转换,例如:
void aUnaryFunction(int a1)
{
/* .... */
}
void doSomethingWithFn()
{
typedef void(*BinaryFn)(int, const char*);
BinaryFn aBinaryFunction = (BinaryFn) &aUnaryFunction;
aBinaryFunction (3, "!!!");
}
永远不应该完成,根据C标准,“未定义的行为”也是如此。
但是我不明白为什么,考虑到函数调用在C中的工作方式,这个例子并不安全。我所做的只是无视一个论点。
假设int第一个参数的处理是一致的,所有会发生的事情是当doSomethingWithFn()
调用aBinaryFunction
aUnaryFunction
时,const char *将被放入寄存器中按预期运行,并且在aUnaryFunction
期间可能会覆盖const char *,但这没关系,因为无论如何其他任何东西都不会使用它。
我在这里遗漏了什么,或者这实际上是安全的吗? (或两者之间,或两者兼而有之?)
答案 0 :(得分:6)
问题是没有一个“方式函数调用在C中工作” - 只有函数调用在特定C实现上工作的方式。
作为一个具体的例子,“被调用者清理”调用约定(如x86 stdcall
)要求被调用者知道有多少参数被推送到堆栈以执行正确的清理,这将被颠覆你的榜样。
答案 1 :(得分:5)
这归结为调用约定。如果参数以相反的顺序“发送”,例如怎么办?或者,如果有一个标准过程必须在依赖正确数量的参数的函数调用之后完成?
你提出的建议可能有用,但你不应该依赖于此,并且标准将此属性定义为未定义的行为。
答案 2 :(得分:0)
顺便说一句,“未定义的行为”是“不要做它,它不安全!”的密码。
它表示它不能在同一台机器上的不同机器上运行,甚至不能在同一编译器的不同版本上运行。