d取非静态方法地址
struct S {
int m(int x) {return x;}
}
void main() {
int function(int) func = &S.m;
writeln(func(5));// 不打印5!
}
不应编译.
我一直在研究该问题,似乎,令人惊讶的是,这是期望行为.我先修复它,但后来发现,这是正确代码.
现在,当谈论函数时,有两类:函数或闭包.函数由函数指针表示,而闭包由函数和环境指针表示.
当取成员函数地址时,编译器只是简单地设置函数指针为函数代码地址.然而,(静态除外的)成员函数也有在后台按第一个参数传递的环境指针.所以在报告代码中,最终得到如下代码:
int m(void* ctx, int x)
{
return x;// mov rax, rsi
//返回第2个参数
}
void main()
{
int function(int) func = &S.m;
// mov rax, m
func(5);
//mov rdi,5;
//jmp rax
}
因此得到了垃圾.你得到了函数地址,然后就像它只有一个参数一样欺骗编译器,调用m.注意,如果函数的类型是闭包,那么你正确得到了5,因为现在编译器知道把ctx(本例中是null)传递给m了.
不带环境取成员函数实际地址是很有用的.测试包中很多,如果禁止它,就别无选择.另一方面,如果用@safe标记main,就不能编译代码:
在安全代码中,要取`myFunc`成员地址,必须要加`this`.
因此,在安全代码中这是禁止的,但了解它的高级用户可用此功能.
所以这是无效错误报告.
没有环境指针,不应调用闭包的函数指针.
但可手动,设置环境和函数指针:
struct S {
int m(int x) {return x;}
}
void main() {
import std.stdio;
int function(int) func = &S.m;
int delegate(int) func2;
S s;
func2.funcptr = func;
func2.ptr = &s;
writeln(func2(5));
}
&S.m返回函数指针,所以,函数是可调用的.用户确保正确使用它们.现在不能禁止取S.m的地址.而改&S.m类型,会产生更多问题.
浙公网安备 33010602011771号