c - 当您使用 void (*)() 指针调用返回 int 的函数时会发生什么?

标签 c windows assembly calling-convention

我想知道在这种情况下会发生什么:

int foo()
{
    return 1;
}
void bar()
{
    void(*fPtr)();
    fPtr = (void(*)())foo;
    fPtr();
}

将返回int的函数地址赋值给void(*)()类型的指针,并调用指向的函数。

  1. 标准对此有何规定?
  2. 无论第一个问题的答案如何:我们这样调用函数安全吗?实际上,结果不应该只是被调用者 (foo) 将某些内容放入 EAX/RAX 而调用者 (bar) 将忽略 rax 内容并继续执行程序吗?我对 Windows 调用约定 x86 和 x64 很感兴趣。

非常感谢您的宝贵时间

最佳答案

1) 来自 C11 标准 - 6.5.2.2 - 9

If the function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function, the behavior is undefined

明确指出,如果使用与定义它的类型不匹配的类型的指针调用函数,则会导致未定义行为。 但是 Actor 还可以。

2) 关于你的第二个问题 - 如果调用约定 XXX 和实现 YYYY 定义明确 -

您可能已经反汇编了一个示例程序(即使是这个)并发现它“有效”。但是有轻微的并发症。你看,现在的编译器非常聪明。有一些编译器能够执行精确的过程间分析。某些编译器可能会发现您有未定义的行为,并且可能会做出一些可能会破坏该行为的假设。

一个简单的例子-

因为编译器发现这个函数是用 void(*)() 类型调用的,它会假设它不应该返回任何东西,它可能会删除返回所需的指令正确的值。

在这种情况下,调用此函数的其他函数(以正确的方式)将获得错误的值,因此会产生明显的不良影响。

PS:正如@PeterCordes 所指出的,任何现代、健全和有用的编译器都不会有这样的优化,使用这样的调用可能总是安全的。但答案和示例(可能过于简单)的目的是提醒人们在处理 UB 时必须非常小心。

关于c - 当您使用 void (*)() 指针调用返回 int 的函数时会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47072443/

相关文章:

c - 用一个物理定时器模拟多个虚拟定时器

c - 寻找多个目标字符时解析单词的最佳方法是什么

assembly - 在repz cmpsb之后,汇编指令 'seta'和 'setb'做了什么?

c++ - 包括来自 C++ 的 C-DLL

windows - 如何创建 Visual Studio 2012 聊天框控件?

assembly - 使用 NASM 在 64 位模式下不支持 pop 指令?

go - 是否可以在 Go 代码中包含内联汇编?

c - 添加时 Struct 的地址不一致

c - 在 C 中标记字符串?

java - Swing - 更改 Windows 主题会重置自定义边框、插图和背景