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类型,会产生更多问题.

posted @   zjh6  阅读(15)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示