Должен ли я предпочесть соглашение о вызовах «по умолчанию», а не __fastcall, когда меня не волнует соглашение о вызовах? - PullRequest
6 голосов
/ 03 мая 2011

У нас есть огромная кодовая база C ++ с большим количеством COM-объектов. Каждая функция, доступная для COM, должна иметь __stdcall соглашение о вызовах (обычно STDMETHODCALLTYPE макрос), поэтому у нас есть множество функций, помеченных STDMETHODCALLTYPE.

Теперь я вижу функцию, которая не вызывается напрямую через COM, а вызывается только из нашего кода C ++, и эта функция также имеет макрос STDMETHODCALLTYPE в своей подписи. Я полностью уверен, что макрос там бесполезен - никаких вызовов через эту функцию через COM не происходит.

Должен ли я удалить __stdcall, чтобы он стал функцией соглашения о вызовах по умолчанию? Как я принимаю такие решения?

Ответы [ 5 ]

9 голосов
/ 03 мая 2011

Мой подход состоит в том, чтобы использовать соглашение о вызовах компилятора по умолчанию для внутреннего кода и использовать четко определенные соглашения о вызовах для любых методов, экспортируемых через границу модуля.

Соглашение о вызовах по умолчанию для большинствакомпиляторы хорошо используют регистры по соображениям производительности, поэтому при их использовании есть преимущества.Это также делает ваш код проще для глаз, так как вам не нужно указывать соглашение, чтобы получить значение по умолчанию.

Для экспортируемых функций вам явно необходимо указать соглашение.Если вы создаете библиотеку, которая, как вы ожидаете, будет вызываться из языков, отличных от C или C ++, было бы общепринятым использовать stdcall.Если вы ожидаете только клиентов C или C ++, вероятно, cdecl является наиболее распространенным соглашением.

5 голосов
/ 03 мая 2011

Когда Windows переключилась с __ cdecl на _ _stdcall в качестве соглашения о вызовах по умолчанию, размер продукта упал примерно на 10%. Эта экономия была полностью связана с удалением корректировок стека после вызова методов stdcall (__cdecl - это соглашение о вызове «вызывающий настраивает стек для удаления параметров», __stdcall - это соглашение о вызове «вызывающий настраивает стек для удаления параметров», так как вызывающие абоненты, чем вызываемые, переключение уменьшает размер ваших двоичных файлов).

Недостатком использования __stdcall является то, что у вас нет переменных # аргументов (так как вызываемый объект корректирует стек, он не может знать, сколько параметров указал вызывающий объект).

Итог: переключение на __stdcall из соглашения о вызовах по умолчанию может привести к уменьшению размера вашего двоичного файла. Это может или не может быть важно для вас.

Однако, как уже упоминалось выше, если ваш код EVER доступен в другом компиленде (например, если вы доставляете файл .lib кому-то еще), абсолютно важно объявить используемое соглашение о вызовах.

3 голосов
/ 03 мая 2011

Единственная причина, по которой материал COM явно устанавливает соглашение о вызовах, заключается в том, что он используется за пределами DLL.
Поэтому я бы посоветовал отказаться от явного параметра соглашения о вызовах и установить его в настройках компилятора.
В общем:
Если функции экспортируются как DLL, установите макрос, который определяет соглашение о вызовах в заголовках.Это не позволяет пользователям из DLL использовать неправильное соглашение о вызовах при связывании с вашей DLL.Явный переопределяет настройку компилятора.
Не используйте конвекцию вызова для локальных функций.Соглашение может быть установлено переключателем компилятора.Если вы решили установить его явно, сделайте это для всех функций.Тогда у вас все еще есть центральное место для изменения соглашения о вызовах.
Конечно, если это имеет смысл, или вам нужно какое-то специальное соглашение о вызовах, например, fastcall для оптимизации, вам также нужно установить явно.

2 голосов
/ 03 мая 2011

Включена ли у вас оптимизация всей программы и генерация кода времени соединения ? Если это так, и вы не экспортируете функцию из вашей DLL или не передаете ей указатели, тогда компилятор может генерировать пользовательские соглашения о вызовах для этой функции или встроить ее (даже если она не определена в заголовочном файле).

1 голос
/ 03 мая 2011

Вы можете просматривать свои карты, чтобы увидеть, есть ли на них ссылки, путем поиска файлов ODL, связанных с решением.Если его там нет, у него нет интерфейса, и вы можете изменить соглашение о вызовах.Существует риск того, что кто-то другой предположит, что все функции настроены в соответствии с этим соглашением о вызовах, и они могут добавить интерфейс позднее.

...