Существуют ли стандартные соглашения о вызовах? - PullRequest
1 голос
/ 09 января 2012

У меня недавно были проблемы с указателями на функции CALLBACK CALLMACK, и это сводилось к использованию соглашений о вызовах, которые временно решали проблему, тогда funy CALLBACK работал хорошо, но сигнатура вызывающей функции все еще была неправильно введена !! и я потратил много времени, чтобы найти эту ошибку. понял, что соглашение о вызовах позволяет вам делать что-то, что иногда не в порядке ...

Хорошо, это уже прошло ... Теперь я хочу узнать немного больше о соглашениях о вызовах: 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.

Ответы [ 2 ]

3 голосов
/ 09 января 2012

Нет; соглашения о вызовах зависят от платформы. Двойное подчеркивание в начале означает, что это концепция, зарезервированная для реализации. Сам язык не предъявляет требований о том, как его реализовать на этом уровне детализации.

1 голос
/ 09 января 2012

Причина сбоя без __cdecl заключается в том, что по умолчанию компилятор Windows использует __stdcall. Последнее заставляет функцию вызываемого абонента очистить стек. Следовательно, ваш вызывающий объект выдвигает два аргумента в стек, чтобы вызвать «Trigger», но Trigger выталкивает только один аргумент из стека при выходе из функции. Следовательно, вы терпите крах. __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;

Потому что, если вы этого не сделали, ваш код не скомпилировался. Исправьте ваш код так, чтобы приведение не требовалось для компиляции, и ваша реальная ошибка исчезнет так же, как и ваша ошибка.

...