Я знаю, что __ stdcall функции не может иметь замещающих знаков, но я хочу быть уверенным, что нет никаких платформ, которые поддерживают функции stdarg.h для соглашений о вызовах кроме __ cdecl или __ stdcall.
Соглашение о вызове должно быть таким, чтобы вызывающая сторона очищала аргументы из стека (потому что вызывающая сторона не знает, что будет передано).
Однако это не обязательно соответствует тому, что Microsoft называет "__cdecl". Например, на SPARC аргументы обычно передаются в регистрах, потому что так устроен SPARC - его регистры в основном действуют как стек вызовов, который высыпается в основную память, если вызовы становятся настолько глубокими, что уже не помещаются в регистр.
Хотя я менее уверен в этом, я бы ожидал примерно того же на IA64 (Itanium) - у него тоже огромный набор регистров (несколько сотен, если мне не изменяет память). Если я не ошибаюсь, он немного более свободен в использовании регистров, но я бы ожидал, что они будут использоваться аналогично, по крайней мере, большую часть времени.
Почему это имеет для вас значение? Смысл использования stdarg.h и его макросов в том, чтобы скрыть от вашего кода различия в соглашениях о вызовах, чтобы он мог работать с переменными аргументами переносимо.
Редактирование, на основе комментариев: Хорошо, теперь я понимаю, что вы делаете (по крайней мере, достаточно, чтобы улучшить ответ). Учитывая, что у вас уже (очевидно) есть код для обработки вариаций в ABI по умолчанию, все стало проще. Остается только вопрос о том, всегда ли переменные функции используют "стандартный ABI", каким бы он ни был для данной платформы. С "stdcall" и "default" в качестве единственных опций, я думаю, что ответ на этот вопрос - да. Например, в Windows, wsprintf
и wprintf
нарушают это правило и используют соглашение о вызове cdecl вместо stdcall.
Самый точный способ определить это - проанализировать соглашения о вызовах. Для работы вариативных функций вашему соглашению о вызовах требуется пара атрибутов:
printf
, спецификация формата. Кроме того, адрес самого списка аргументов переменных также должен быть получен из известного местоположения.) stdcall
не будет работать, потому что вызываемый объект отвечает за извлечение параметров из стека. В старые времена 16-битной Windows pascal
не работал, потому что он помещал параметры в стек слева направо.
Конечно, как упоминалось в других ответах, многие платформы не дают вам никакого выбора с точки зрения соглашения о вызовах, что делает этот вопрос неактуальным для тех.
Вы имеете в виду «платформы, поддерживаемые MSVC» или как общее правило? Даже если вы ограничитесь платформами, поддерживаемыми MSVC, у вас все равно будут ситуации, подобные IA64 и AMD64 где есть только «одно» соглашение о вызовах, и это соглашение о вызовах называется __ stdcall
, но это определенно не то же самое __ stdcall
, которое вы используете на x86.
AFAIK, разнообразие соглашений о вызовах уникально для DOS / Windows на x86. На большинстве других платформ компиляторы поставлялись с ОС и стандартизировали соглашения.