是否存在标准调用约定?

发布于 2024-12-26 04:17:37 字数 858 浏览 0 评论 0原文

我最近遇到了 custm CALLBACK 函数指针的问题,这归结为使用暂时解决问题的调用约定,有趣的 CALLBACK 确实工作得很好,但调用函数的签名仍然是错误的!我花了很多时间来找出这个BUG。 意识到调用约定有时会让你做一些不正常的事情...

好吧,现在已经过去了...现在,我想更多地了解调用约定: Visual Studio 有自己的 __cdecl__thiscall 等 (IIRC)。

标准 C++ 是否规定了一些调用约定?如果是,我该如何使用它们?


编辑:我未能找到错误的一些代码:(

    class Object;
    class EventArgs;

    typedef void(__cdecl Object::*MethodHandler)(Object* sender, EventArgs args);

///..... this is how I call it..(snapshot)
(iter->second.sender->*iter->second.memberFunct)(sender, args);
///...
    void __cdecl Triger(EventArgs args) //missing "Object* sender" here!!! but it works!
    {
        if(args == "test")
        cout << "test args received" << endl;
    }

顺便说一句,类型名称是我的自定义类。) 效果很好!函数被调用但没有 __cdecl 我收到了 ESP 寄存器错误。

I've recently having problems with custm CALLBACK's function pointers, and that boiled down into using calling conventions which solve the problem temporaly, funy CALLBACK did work well then but signature of the calling function was still misstyped!! and I've spend a lot of time finding that BUG out.
realized that caling convention let you do something what isn't OK sometimes...

OK that's past now... Now, I want to know a litle more about calling conventions:
Visual Studio has it's own __cdecl, __thiscall, etc (IIRC).

Does standard C++ regulates some calling conventions and how can I use them if so?


EDIT: Some code on which I failed to find a bug:

    class Object;
    class EventArgs;

    typedef void(__cdecl Object::*MethodHandler)(Object* sender, EventArgs args);

///..... this is how I call it..(snapshot)
(iter->second.sender->*iter->second.memberFunct)(sender, args);
///...
    void __cdecl Triger(EventArgs args) //missing "Object* sender" here!!! but it works!
    {
        if(args == "test")
        cout << "test args received" << endl;
    }

(BTW, type names are my custom classes.)
That worked just fine! Function was called but without __cdecl I have received ESP register errors.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

嘦怹 2025-01-02 04:17:37

不;调用约定是特定于平台的。前导的双下划线表明这是一个实现保留的概念。语言本身对如何在这种详细程度上实现没有任何要求。

No; calling conventions are platform specific. The leading double underscore is a clue that this is an implementation-reserved concept. The language itself makes no requirements about how it is to be implemented at this level of detail.

a√萤火虫的光℡ 2025-01-02 04:17:37

没有__cdecl而崩溃的原因是因为Windows编译器默认使用__stdcall。后者强制被调用函数清理堆栈。因此,您的调用者将两个参数推入堆栈以调用“触发器”,但触发器仅在函数退出时从堆栈中弹出一个参数。因此,你崩溃了。 __cdecl 调用约定可以解决这个问题。

正如我在上面的评论中所说,使用 __cdecl 修复崩溃隐藏了真正的错误。您的触发器参数列表与“MethodHandler”预期的参数列表不匹配。这很可能就是导致你崩溃的原因。

这可能是一个更好的解决方案:

typedef void(Object::*MethodHandler)(Object* sender, EventArgs args);

void Triger(Object* sender, EventArgs args)
{
    if(args == "test")
    cout << "test args received" << endl;
}

您没有共享显示如何为后续回调注册“触发器”的代码。但我强烈怀疑你已经做了这样的转换:

MethodHandler handler = (MethodHandler)Trigger;

因为如果你不这样做,你的代码就无法编译。修复您的代码,以便编译时不需要强制转换,并且真正的错误和崩溃都会消失。

The reason why you crash without __cdecl is because the Windows compiler default is to use __stdcall. The latter forces the callee function to cleanup the stack. Hence, your caller is pushing two arguments on to the stack to invoke "Trigger", but Trigger is only popping one argument off the stack on function exit. Hence, you crash. __cdecl calling convention kind of gets around this.

As I said in my comments above, using __cdecl to fix the crash is hiding the real bug. Your argument list of trigger is not matching the argument list expected of "MethodHandler". That's likely the cause of your crash.

This is likely a better fix:

typedef void(Object::*MethodHandler)(Object* sender, EventArgs args);

void Triger(Object* sender, EventArgs args)
{
    if(args == "test")
    cout << "test args received" << endl;
}

You didn't share the code that shows how "Trigger" gets registered for a subsequent callback. But I strongly suspect you have put a cast of something like this:

MethodHandler handler = (MethodHandler)Trigger;

Because if you didn't do that, your code didn't compile. Fix your code such that the cast isn't needed for compile, and your real bug goes away as well as your crash.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文