微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

是否可以显式调用名称混乱的函数?

如何解决是否可以显式调用名称混乱的函数?

假设我有类似的东西

struct Foo {
    void goo() {printf("Test");}
}

external void _ZN3Foo3gooEv(Foo *f);

int main() {
        Foo f;
        _ZN3Foo3gooEv(&f);
}

是否可以通过此处函数名称修改版本来调用Foo :: goo()?

编辑:

为澄清起见,这只是一个实验,以查看是否有可能显式调用名称错误函数。这里没有进一步的目标。

我认为所有成员函数基本上都将this指针作为其第一个参数。

我知道这不会链接,但是我不明白为什么。我认为名称重整是在编译时发生的,并且当链接程序运行时,它将解析对名称重整函数调用。 (这就是为什么我认为如果我们将_ZN3Foo3gooEv保留为extern,它将转到符号表中进行查找。)

在这里误会了吗?

解决方法

可以,但有一些警告。

您必须以某种方式使用成员函数来生成代码,或者使其不内联,并且错误的定义应为extern "C"以防止“双重错误”。例如:

#include <cstdio>

struct Foo {
    const char* message;
    void goo();
};

void Foo::goo() {
    std::printf("%s",this->message);
}

extern "C" void _ZN3Foo3gooEv(Foo *f);

int main() {
        Foo f{ "Test" };
        _ZN3Foo3gooEv(&f);
}

可以正常工作,并且在gcc中特别稳定。

之所以可行,是因为在大多数系统上,成员函数的调用约定与自由函数的默认调用约定等效。 this就像是第一个参数一样传递给成员函数,显式参数占据后面的arg传递槽。 (寄存器和/或堆栈)。我相信至少在x86-64,ARM 32位和64位以及Windows之外的32位x86上确实如此。

clang似乎特别支持这种用例:当gcc假装Foo::goomain是两个单独的实体时,它将_ZN3Foo3gooEv内联到Foo::goo中(因此可以'不会被替换并内联)。

使用MSVC,您可以执行类似的操作。但是,在Windows上的x86-32代码中,使用调用约定__thiscall,而不是将this指针作为第一个参数传递,而是与栈中的其他args一起传递给ECX寄存器。如果使用clang或gcc对x86-32进行交叉编译,则可以使用[[gnu::thiscall]]__attribute__((thiscall)))。 ({fastcall类似,如果只有一个arg,但是有2个args将传递寄存器中的前2个,而不仅仅是前1个。)


但是确实没有理由这样做。它只能被视为编译器扩展(因为它使用_Capital符号),并且,如果您需要从C调用这些函数的方法,请使用在C ++转换单元中定义的助手void Foo_goo(struct Foo*) 。它也可以调用私有成员函数,但是您已经可以通过模板专门化以符合标准的方式进行此操作。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。