Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 89, средняя оценка - 4.75
Ze
3 / 3 / 0
Регистрация: 30.10.2010
Сообщений: 12
#1

Реализация __stdcall, __cdecl - C++

30.10.2010, 19:07. Просмотров 11406. Ответов 14
Метки нет (Все метки)

Всем добрый день!
Изучаю COM средствами C++. Смысл спецификаторов, указанных мною в заголовке мне понятен, но я хочу для понимания знать, "как что" они реализовываются. Информации по данному вопросу я найти не смог (допускаю, что не там или не так искал) и начал подозревать, что это ключевые слова самого C++, однако Qt, например, об __stdcall говорит следующее:

#define __stdcall __attribute__((__stdcall__))

то есть, это все же не "зарезервированное слово" языка C++. Буду благодарен, если кто-то мне объяснит, чем эти спецификаторы является в терминологии C++.
Лучшие ответы (1)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Nick Alte
Эксперт С++
1603 / 995 / 118
Регистрация: 27.09.2009
Сообщений: 1,918
Завершенные тесты: 1
30.10.2010, 19:32     Реализация __stdcall, __cdecl #2
Это специфические для компилятора расширения. Конвенции вызова не прописаны в стандарте C++, но нужны для жизни, так что разные компиляторы могут определять конвенции разными словами.
Ze
3 / 3 / 0
Регистрация: 30.10.2010
Сообщений: 12
30.10.2010, 19:36  [ТС]     Реализация __stdcall, __cdecl #3
То есть, их можно понимать как что-то вроде "директив компилятора"?
Nick Alte
Эксперт С++
1603 / 995 / 118
Регистрация: 27.09.2009
Сообщений: 1,918
Завершенные тесты: 1
30.10.2010, 20:57     Реализация __stdcall, __cdecl #4
Не совсем, их можно понимать как расширение языка, специфическое для компилятора - это ключевые слова, не описанные в стандарте.
Ze
3 / 3 / 0
Регистрация: 30.10.2010
Сообщений: 12
03.11.2010, 17:06  [ТС]     Реализация __stdcall, __cdecl #5
Прочитал некоторое количество довольно неплохих, на мой взгляд, книг по C++. Вот первая, в которой подобные конструкции встретились, и даются в примерах без особого объяснения...
Вот тоже из этой серии:

C++
1
2
3
BOOL APIENTRY DllMain(HANDLE hModule,
                      DWORD dwReason,
                      void* lpReserved)
BOOL - понятно, тип, DllMain - имя функции. Но что такое APIENTRY? Тоже специальный "тип" какой-то? Имя какой-то переменной?
Вот __stdcall называют "спецификатором". Что такое спецификатор? Почему в книгах по C++ вообще такого термина нет? Я хочу понять не "для чего это надо", а "что это такое". Понять синтаксис. Где еще, например, можно подобное вставлять кроме как перед функциями... Суть, короче говоря.

Может быть есть хорошие источники информации именно по этому вопросу...
Спасибо.
KpeHDeJIb
56 / 56 / 3
Регистрация: 31.10.2010
Сообщений: 103
03.11.2010, 17:15     Реализация __stdcall, __cdecl #6
Цитата Сообщение от Ze Посмотреть сообщение
#define __stdcall __attribute__((__stdcall__))
Ну это для GCC, вообще по поводу конвенций вызова функции читай тут http://en.wikipedia.org/wiki/Calling_convention
Nick Alte
Эксперт С++
1603 / 995 / 118
Регистрация: 27.09.2009
Сообщений: 1,918
Завершенные тесты: 1
03.11.2010, 21:16     Реализация __stdcall, __cdecl #7
APIENTRY - спецификатор типа вызова. Делается обычным макросом в составе <windows.h> навроде
C++
1
#define APIENTRY __stdcall
под конкретную версию компилятора - чтобы одинаково описывать функции для разных компиляторов. Очевидно, что и про BOOL, и про APIENTRY и даже про DllMain пишут в MSDN.
Ze
3 / 3 / 0
Регистрация: 30.10.2010
Сообщений: 12
04.11.2010, 10:24  [ТС]     Реализация __stdcall, __cdecl #8
То, что APIENTRY это спецификатор вызова, и что
C++
1
#define APIENTRY __stdcall
я знаю.
BOOL и даже DllMain трудностей в понимании не составляют.
Вопрос был больше о самих спецификаторах. Насколько я вижу, у них даже имена не однотипны, чтобы они в синтаксисе выделялись как-то (syscall, pascal, cdecl, ...)
Спасибо за ответы.
Просто меня удивило то, что в том же C++ PRIMER Липпмана, где детально разбираются довольно серьезные нюансы языка, о типах вызовов и способах их задания ни слова не написано, а его называют одним из лучших учебников...
Nick Alte
Эксперт С++
1603 / 995 / 118
Регистрация: 27.09.2009
Сообщений: 1,918
Завершенные тесты: 1
04.11.2010, 12:46     Реализация __stdcall, __cdecl #9
Конвенции вызова имеют мало отношения к языку, а Липпман рассказывает прежде всего о чистом незамутнённом C++. Но когда наивному программисту с пылающим взором приходится сталкиваться с реальным миром, он обнаруживает, что приходится взаимодействовать с программными модулями, написанными разными людьми и даже - о, ужас! - на других языках. Например, злые языки поговаривают, что тот же Windows был написан на паскале, откуда и спецификатор __stdcall на всём, что с этим API связано (раньше __stdcall по-свойски именовали просто pascal). Да и __cdecl тоже сиплюсплюсу не родной, а уходит корнями в Си (и вы-таки не объявите перегруженные функции с таким модификатором).
То есть, это всё лежит за пределами собственно языка и касается скорее взаимодействия с другими средствами.
nxnx
Формучанин
362 / 293 / 16
Регистрация: 02.11.2010
Сообщений: 1,234
04.11.2010, 13:39     Реализация __stdcall, __cdecl #10
Соглашение вызова
Ze
3 / 3 / 0
Регистрация: 30.10.2010
Сообщений: 12
04.11.2010, 13:53  [ТС]     Реализация __stdcall, __cdecl #11
Спасибо за объяснения.
Я не стал бы это называть "ужасом"
("приходится взаимодействовать с программными модулями, написанными разными людьми и даже - о, ужас! - на других языках").
На мой взгляд, в книгах, претендующих на "лучшие учебники" об этом было бы полезно полезно говорить "наивному программисту с пылающим взором", несмотря на то, что это не оговаривает стандарт. Так как этот механизм только расширяет пределы практической применимости языка, ведь реальные программы не пишутся ради программирования, как Вы правильно заметили "приходится сталкиваться с реальным миром".

nxnx, спасибо, уже знаком с этой статьей.
Evg
Эксперт CАвтор FAQ
17286 / 5534 / 345
Регистрация: 30.03.2009
Сообщений: 15,059
Записей в блоге: 26
03.03.2011, 20:59     Реализация __stdcall, __cdecl #12
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Ze, в стандарте Си++ о них ничего не написано, потому что языки программирования для того и придумывают, чтобы программист мог работать, не задумываясь о том, как реально при исполнении задачи будут передаваться параметры. А все правила передачи параметров на низком уровне описываются в программных соглашениях (ABI - application binary interface) для каждого конкретного процессора (а иногда даже на одном процессоре под разными операционными системами могут быть разные соглашения). В случае процессора x86, как мы видим, даже в рамках одной операционной системы существуют различные программные соглашения. И все эти модификаторы - это расширения исключительно компиляторов для платформы x86 (а не свойства языка Си++).

На самый интересный вопрос "а зачем сделано несколько программных соглашений" я чёткого ответа дать не могу. равно как его и нет в указанной статье. Но могу предположить, что делается это для ускорении кода. Программные соглашения пишутся таким образом, что они работают во всех случаях жизни: даже если подано тысячу параметров. Но при этом в жизни существует ряд частных случаев.

Например, функция с маленьким числом параметров (1-2-3 параметра). И имеется целая цепочка вызовов таких функций, при этом функции являются короткими. Ситуация характерна для всяких обработчиков ситуаций, когда функция-обработчик реально представляет собой прокладку для вызова другой функции, в том числе и какой-нибудь функции из базового класса в цепочке наследований. При таком раскладе если мы будем передавать параметры через стек, каждый раз его настраивая в функции или в точке вызова, то для прохождения такой цепочки вызовов коротких функций будут сравнительно большие затраты: очень много работы со стеком, причём работы тупой, потому что мы фактически будем заниматься только копированием параметров. Для таких случаев был заведён тип программного соглашения fastcall, при котором аргументы передаются на регистрах. А потому такая цепочка отработает очень быстро, не залезая в память (что важно на современных процессорах, потому как доступы в память являются "медленными"). Более того, если функция просто транзитно передаёт аргументы в другую функцию, то их даже копировать не надо, потому что входящие и исходящие параметры передаются на тех же самых регистрах.

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

Ну вот что-то типа того

Добавлено через 1 минуту
Цитата Сообщение от Nick Alte Посмотреть сообщение
Конвенции вызова
Вот это я называл словами "программные соглашения". Так, на всякий случай, тем кто привык к другой терминологии
Kastaneda
Форумчанин
Эксперт С++
4259 / 2791 / 219
Регистрация: 12.12.2009
Сообщений: 7,120
Записей в блоге: 1
Завершенные тесты: 1
03.03.2011, 21:13     Реализация __stdcall, __cdecl #13
Цитата Сообщение от Evg Посмотреть сообщение
Но могу предположить, что делается это для ускорении кода.
Или по другим причинам. После вызова ф-ции кто-то должен выровнять стек. По соглашению С (Си) этим занимается вызывающая процедура, а по соглашению PASCAL - вызываемая. Соглашение С полезено когда неизвестно, как много паpаметpов будут пеpеданны функции, как напpимеp, в случае printf(), когда функция не может знать заpанее, сколько паpаметpов будут положены в стек, так что она не может его уpавнять.
Evg
Эксперт CАвтор FAQ
17286 / 5534 / 345
Регистрация: 30.03.2009
Сообщений: 15,059
Записей в блоге: 26
03.03.2011, 21:24     Реализация __stdcall, __cdecl #14
Kastaneda, я слишком плохо знаю i386, чтобы вести об этом разговор У всех нормальных людей есть два указателя стека - frame pointer и stack pointer (указывают на начало и конец текущего фрейма). Входящие параметры отсчитываются от frame pointer, исходящие - от stack pointer. При исполнении операции вызова автоматически или полуавтоматически происходит замета текущего sp на fp, а вызванная функция выделает себе нужное место и формирует новый sp. И только на i386 как всегда всё через ж...у сделано, потому что на дворе уже третье тысячелетие, а у них до сих пор регистров раз два и обчёлся
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.03.2011, 11:55     Реализация __stdcall, __cdecl
Еще ссылки по теме:

Error LNK2019: unresolved external symbol "public: __cdecl videoInput::videoInput(void)" C++
Ошибка: ссылка на неразрешенный внешний символ "void __cdecl fifth(int)" (?fifth@@YAXH@Z) C++
C++ Ошибка LNK2019 ссылка на неразрешенный внешний символ _main в функции "int __cdecl invoke_main(void)"
__stdcall в файле Dll и его использование в екселе C++
Ошибки error C2296: -: недопустимо, левый операнд имеет тип "double (__cdecl *)(double,double,double C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Ze
3 / 3 / 0
Регистрация: 30.10.2010
Сообщений: 12
04.03.2011, 11:55  [ТС]     Реализация __stdcall, __cdecl #15
Evg, хорошее объяснение.
Yandex
Объявления
04.03.2011, 11:55     Реализация __stdcall, __cdecl
Ответ Создать тему
Опции темы

Текущее время: 21:29. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru