Нужно ли добавлять к этой функции префикс __stdcall?

Изучая отладку OpenGL, я реализовал функцию обратного вызова, которая будет получать любые сообщения об ошибках отладки из API OpenGL всякий раз, когда что-то пойдет не так. В учебнике сказано, что сигнатура функции:

typedef void APIENTRY funcname(GLenum source​, GLenum type​, GLuint id​,
   GLenum severity​, GLsizei length​, const GLchar* message​, const void* userParam​);

Итак, в Windows я реализовал этот обратный вызов. В Windows APIENTRY определяется для __stdcall. __stdcall Я полагаю, что это специфичное для Windows ключевое слово, определяющее соглашение о вызовах. Позже я перенес свой код на Linux, и для начала мой GCC с Eclipse не распознал APIENTRY, потому что это определение Windows. Поэтому я изменил его на __stdcall, который я не уверен, распознал он или нет, но, несмотря на это, выдал ошибку:

"Ожидаемый инициализатор перед glCheckError_"

Поскольку моя функция обратного вызова недействительна, __stdcall glCheckError_(/Params/). Удаление предисловия __stdcall позволяет программе нормально работать и без него.

Мне интересно, нужен ли этот префикс для Windows или Linux? Забавно то, что добавить __stdcall в сигнатуру функции предложили на веб-странице Khronos, содержащей документацию по OpenGL, поэтому, насколько я могу судить, на ней не следует указывать информацию, специфичную для ОС, поскольку OpenGL является кросс- Платформа. Так нужен ли мне этот префикс __stdcall?


person Zebrafish    schedule 03.10.2017    source источник
comment
Это ключевое слово относится к Visual C++.   -  person Asesh    schedule 03.10.2017
comment
И APIENTRY, и __stdcall, верно? Мне кажется странным, что в документах OpenGL упоминается такой обратный вызов. Потому что это не был учебник для Windows.   -  person Zebrafish    schedule 03.10.2017
comment
APIENTRY определяется как __stdcall   -  person Asesh    schedule 03.10.2017
comment
@Asesh Да, у меня есть соблазн оставить это и подождать, чтобы посмотреть, что произойдет. Это обратный вызов, который вызывается OpenGL API, поэтому я предполагаю, что он не имеет ничего общего с Windows, т. е. Windows не вызывает обратный вызов. Хотя нужен ли этот __stdcall при использовании OpenGL в Windows, я не знаю. Ну я могу попробовать и посмотреть.   -  person Zebrafish    schedule 03.10.2017
comment
__stdcall — это соглашение о вызовах, которое определяет, как параметры помещаются в стек. Я не вижу никаких API-интерфейсов на веб-сайте Khronos, использующих это соглашение о вызовах.   -  person Asesh    schedule 03.10.2017
comment
@Asesh Вот, например, в разделе Тип функции обратного вызова имеет форму: khronos.org /opengl/wiki/Debug_Output#Getting_messages   -  person Zebrafish    schedule 03.10.2017
comment
Если вы не укажете соглашение о вызовах, компилятор будет использовать соглашение о вызовах по умолчанию. В Visual C++ это обычно соглашение о вызовах __cdecl.   -  person Asesh    schedule 03.10.2017


Ответы (1)


В Windows и только под 32-битной, тогда будет разница. (По умолчанию используется соглашение о вызовах __cdecl, в отличие от __stdcall, используемого в openGL). Это может привести к повреждению стека, если вы используете неправильное соглашение (компилятор должен ошибаться, если повезет).

В 64-битных окнах это не имеет значения (поскольку stdcall недоступен, поэтому все __stdcall/__cdecl по умолчанию будут __fastcall).

Это не имеет значения для Linux/macos/android/ios.

Все, что нужно, это обернуть это в макрос.

#if definded(_WIN32) && !defined(_WIN64)
# define STDCALL __stdcall
#else 
# define STDCALL 
#endif
person robthebloke    schedule 03.10.2017
comment
Действительно? Это очень полезно. Я немного поискал, в том числе прочитал несколько ответов здесь на SO о разнице в соглашении о вызовах, этот 32-битный и 64-битный бизнес никогда не упоминался. Спасибо. - person Zebrafish; 03.10.2017
comment
Ага. В 64-битных окнах у вас есть два варианта соглашений о вызовах: __fastcall или __vectorcall, где __vectorcall использует больше регистров при передаче аргументов с плавающей запятой/вектора (вместо возврата к стеку). Все Linux/BSD/Macos используют только __vectorcall (с небольшой разницей в том, какие регистры общего назначения используются - на самом деле это не проблема). Единственный другой вариант, который у вас есть (доступен на всех платформах), - это «extern C» (отключить изменение имени С++) , или не использовать внешний C (включить изменение имени C++). - person robthebloke; 03.10.2017