我正在使用Windows Phone 8上的一个项目,我正在通过指针调用静态函数,但没有参数的类型(我有参数的数量和一个以int或float作为参数的函数类型)
我已经检查了这个帖子What is the Windows RT on ARM native code calling convention?
我也查看了程序集,它似乎从int处理不同的浮点数(在S0中传递的浮点数)。
我的问题是,有没有办法强迫某些功能(甚至所有功能)被称为旧时尚?
答案 0 :(得分:0)
好的,我打算通过假装你问底层的问题来澄清事情:
当我只有一个通用的
(void *)(float)
指针时,如何调用(void *)(int)
函数?
直接跳到询问如何更改调用约定听起来如下:
如何让一个实现的未定义行为表现得像另一个实现的未定义行为,因为我编写了大量依赖于此并且不想修复它的代码?
首先,让我们看看C标准说的是什么......
是的,有问题。悲伤的脸:(如果转换的指针用于调用类型与指向类型不兼容的函数,则行为未定义。
但是等一下,上一句话说的是什么?
指向一种类型的函数的指针可以转换为指向另一种函数的指针 打字再回来;结果应该等于原始指针
万岁,我们可以用一种定义明确的方式来做,而不需要求助于垫片和装配黑客,只需在我们打电话时转换回正确的功能签名即可!
总之; 强制转换函数指针,而不是参数,并且它不仅会起作用,而且正确 。由于你必须知道你正在调用的函数的真实签名(否则你无法传递适当的参数),你总是可以进行正确的强制转换,并且中间指针类型变为非问题。
这是一个演示:
#include <stdio.h>
void fn(float x){
printf("%.1f\n", x);
}
int main(void) {
float f = 27.3;
void (*fptr)(float) = fn;
void (*iptr)(int) = fn; /* LA LA COMPILER WARNING I CAN'T HEAR YOU */
printf("expected:\t");
fptr(f);
printf("casting arg:\t");
iptr(*(int *)&f); /* double-undefined behaviour */
printf("casting iptr:\t");
((void(*)(float))iptr)(f);
}
请注意,*(int *)&f
本身是未定义的,但在这种情况下(VS2013),“预期”代码(在没有转换的情况下用作int的float)确实会在两个版本中生成。嘿,这是一种有效的未定义行为形式(就像其他任何东西 ......)
输出:
expected: 27.3
casting arg: 27.3
casting iptr: 27.3
Press any key to continue . . .
咦?何必?这两种方法都“有效”。我们来试试x64构建......
expected: 27.3
casting arg: 0.0
casting iptr: 27.3
Press any key to continue . . .
阿。它就是。事实上,如果你在其他3个当前支持的Windows平台上编写原始代码,你就不会遇到这个问题,因为它不会起作用 - x86-64,IA-64和ARM都使用基于寄存器的调用约定,浮点数和整数分别处理,而x86是基于堆栈的不合时宜。
或者,如果你真的真的想要一个可移植的尝试来利用未定义的行为,请尝试重写所有函数以在真实参数之前加载虚拟整数和浮点数,并且之后类似的负荷和浮子负荷,以确保中间的那些在不考虑评估顺序的情况下溢出到堆中。是的,那将是疯狂 ......