Mar*_* K. 3 c windows assembly calling-convention
我想知道在这种情况下会发生什么:
int foo()
{
return 1;
}
void bar()
{
void(*fPtr)();
fPtr = (void(*)())foo;
fPtr();
}
Run Code Online (Sandbox Code Playgroud)
函数返回int的地址被赋给void(*)()类型的指针,并调用指向的函数.
非常感谢你的时间
1)从C11标准 - 6.5.2.2 - 9
如果函数定义的类型与表示被调用函数的表达式指向的类型(表达式)不兼容,则行为未定义
清楚地说明,如果使用与其定义的类型不匹配的类型的指针调用函数,则会导致未定义的行为.但演员阵容还可以.
2)关于你的第二个问题 - 如果定义明确的电话会议XXX和实施YYYY -
你可能已经拆解了一个示例程序(甚至是这个程序),并发现它"有效".但是有轻微的并发症.你看,这些天的编译器非常聪明.有些编译器能够执行精确的过程间分析.某些编译器可能会发现您的行为未定义,并且可能会做出一些可能会破坏行为的假设.
一个简单的例子 -
由于编译器发现此函数是使用类型调用的void(*)()
,因此它将假定它不应返回任何内容,并且它可能会删除返回正确值所需的指令.
在这种情况下,调用此函数的其他函数(以正确的方式)将得到一个错误的值,因此它会产生明显的不良影响.
PS:正如@PeterCordes所指出的,任何现代的,理智的和有用的编译器都不会有这样的优化,并且使用这样的调用可能总是安全的.但答案的意图和例子(可能过于简单化)是提醒人们在处理UB时必须非常小心.
实践中会发生什么很大程度上取决于编译器如何实现这一点。您假设 C 只是 asm 上的一个薄(“明显”)层,但事实并非如此。
在这种情况下,编译器可以看到您正在通过类型错误的指针(具有未定义的行为1)调用函数,因此理论上它可以编译bar()
为:
bar:
ret
Run Code Online (Sandbox Code Playgroud)
编译器可以假设在程序执行期间永远不会发生未定义的行为。调用bar()
总是导致未定义的行为。因此编译器可以假设bar
永远不会被调用并基于此优化程序的其余部分。
1 C99,6.3.2.3/8:
如果使用转换后的指针调用类型与指向类型不兼容的函数,则行为未定义。
归档时间: |
|
查看次数: |
691 次 |
最近记录: |