Соглашение вызова fastcall не может использоваться на современных процессорах
Соглашение о вызовах должно быть одинаковым в объявлении и определении
В VC ++ соглашение о вызовах является частью типа функции,Следовательно, соглашение о вызовах объявления и определения функции должно быть одинаковым. Вы не можете просто иметь соглашение о вызовах в объявлении, и определение не отличается от объявления или не отличается от него.следующим образом:
[code3] Неправильно используйте один:
error C2373: ‘add’: redefinition; different type modifiers
error C2440: ‘initializing’: cannot convert from ‘int (__stdcall *)(int,int)’ to ‘int’
[Code4] Два неправильных использования:
error C2373: ‘add’: redefinition; different type modifiers
error C2440: ‘initializing’: cannot convert from ‘int (__cdecl *)(int,int)’ to ‘int’
[Code5] Три неправильных использования:
error C2373: ‘add’: redefinition; different type modifiers
error C2440: ‘initializing’: cannot convert from ‘int (__stdcall *)(int,int)’ to ‘int’
[Code6] Правильное использование:
Познакомьтесь с соглашениями о вызовах Visual Studio __cdecl, __stdcall и __fastcall
Те, кто имеет определенный опыт разработки на C ++, должны быть знакомы с "__cdecl, __stdcall, __fastcall"! Но ты действительно понимаешь? Да, я собрал здесь бесчисленные ямы, посадил бесчисленные каблуки и, наконец, у меня нет другого выбора, кроме как подвести итог (хотя у меня уже есть возможность решить большинство из этих проблем)!
функциональнаяСоглашение о вызовахКак следует из названия, это ограничение и спецификация (спецификация) для вызовов функций, описывающая, как передаются параметры функций и кто очищает стек. Он определяет следующее: (1) порядок, в котором параметры функции помещаются в стек, (2) извлекает ли вызывающий или вызываемый объект параметры из стека, и (3) и метод генерации имени модификатора функции.
Мы знаем, что функция состоит из следующих частей: Тип возвращаемого значения Имя функции (список параметров), например:
【code1】
Выше перечислены хорошо известные компоненты, на самом деле, есть еще некоторые компоненты функции, то есть соглашение о вызовах. следующим образом:
【code2】
Вышеупомянутые __cdecl и __stdcall являются соглашениями о вызовах, где __cdecl - соглашение о вызовах по умолчанию для C и C ++, поэтому обычно наш код определяется как в [code1], компилятор будет использовать для нас соглашение о вызовах __cdecl по умолчанию. Распространенными соглашениями о вызовах являются __cdecl, __stdcall и fastcall, а наиболее широко используются __cdecl и __stdcall, которые мы подробно опишем ниже. , Есть также некоторые необычные, такие как __pascal, __thiscall, __vectorcall.
Remarks
/Gd параметр по умолчанию задает соглашение о вызове __cdecl для всех функций, кроме функций и функций элементов C++, которые помечены как __stdcall, __fastcallили __vectorcall.
/Gr __fastcall указывает соглашение о вызовах для всех функций, кроме функций элементов C++, функций с именами main и функций, которые помечены как __cdecl , __stdcall или __vectorcall . Все функции __fastcall должны иметь прототипы. Это соглашение о вызовах доступно только в компиляторах для 32-разрядных систем и игнорируется компиляторами, предназначенными для других архитектур.
/Gz __stdcall указывает соглашение о вызовах для всех функций, кроме функций элементов C++, функций с именами main и функций, которые помечены как __cdecl , __fastcall или __vectorcall . Все функции __stdcall должны иметь прототипы. Это соглашение о вызовах доступно только в компиляторах для 32-разрядных систем и игнорируется компиляторами, предназначенными для других архитектур.
/Gv __vectorcall указывает соглашение о вызовах для всех функций, за исключением функций-членов C++, функций с именами main , функций с vararg переменным списком аргументов или функций, помеченных конфликтующим __cdecl атрибутом, __stdcall или __fastcall . Это соглашение о вызовах доступно только в 32- и 64-разрядных архитектурах, поддерживающих /arch:SSE2 и более поздние версии, и игнорируется компиляторами, предназначенными для архитектуры ARM.
Функции, принимающие переменное число аргументов, должны иметь пометку __cdecl .
/Gd /Gv , /Gr и /Gz несовместимы с /clr:safe или /clr: pure. Параметры компилятора /clr:pure и /clr:safe не рекомендуется использовать в Visual Studio 2015, и они не поддерживаются в Visual Studio 2017 и более поздних версий.
По умолчанию для процессоров x86 функции элементов C++ используют __thiscall .
Для всех процессоров функция-член, явно помеченная как __cdecl , __fastcall , __vectorcall или __stdcall , использует указанное соглашение о вызовах, если оно не игнорируется в данной архитектуре. Функция-член, принимающая переменное число аргументов, всегда использует соглашение о вызовах __cdecl .
Эти параметры компилятора не влияют на декорирование имен методов и функций C++. Если методы и функции C++ не объявлены как extern "C" , к ним применяется другая схема декорирования имен. Дополнительные сведения см. в статье Внутренние имена.
Дополнительные сведения о соглашениях о вызовах см. в статье Соглашения о вызовах.
Особенности соглашения __cdecl
В 32-разрядных процессорах все аргументы функции передаются в стеке справа налево. В ARM и 64-разрядных архитектурах некоторые аргументы передаются в регистрах, а остальные — в стеке справа налево. Вызывающая подпрограмма извлекает аргументы из стека.
Для языка C соглашение об именовании __cdecl предусматривает использование имени функции с символом подчеркивания перед ним ( _ ). Преобразование регистра не выполняется. Если функции C++ не объявлены как extern "C" , к ним применяется другая схема декорирования имен. Дополнительные сведения см. в статье Внутренние имена.
Особенности соглашения __stdcall
Аргументы функции __stdcall помещаются в стек справа налево. Вызываемая функция извлекает эти аргументы из стека до возврата управления.
Для языка C в __stdcall соглашении об именовании используется имя функции, которому предшествует символ подчеркивания (_), а за ним — символ ( @ ) и размер аргументов функции в байтах. Преобразование регистра не выполняется. В качестве соглашения об именовании компилятор использует следующий шаблон:
3. Конвенция о вызове для VS компилятора
По умолчанию в VS является режим _CDECL, API Windows API использует режим вызова _stdcall в функции экспорта DLL, чтобы сохранить согласованные с API Windows, рекомендуется использовать режим _stdcall
Java.nio.Buffer flip () метод jdk Ошибка перевода на китайский язык
Когда я сегодня читал «Идеи программирования на Java», я столкнулся с методом java.nio.Buffer flip (). Дело в том, что «[color = red] переворачивает этот буфер. Сначала установите ог.
Пример
В следующем примере аргументы передаются в функцию DeleteAggrWrapper в регистрах.
Завершение блока, относящегося только к системам Майкрософт
1. Что такое соглашение о звонке?
Вызов полностью связан с зазором стека. Если вы пишете функцию компиляции, вызовите C / C ++, в режиме _CDECL, функция сборки не нужно очищать стек, в режиме _stdcall, функция сборки должна восстановить стек перед возвратом (RET)
Все белое Введение Сверток Neural Network (CNN)
Пример
В следующем примере компилятору дается инструкция использовать для функции system соглашения об именовании и вызовах C:
Соглашение __fastcall о вызовах указывает, что аргументы для функций должны передаваться в регистрах, когда это возможно. Это соглашение о вызовах применяется только к архитектуре x86. В следующем списке показана реализация этого соглашения о вызовах.
Элемент | Реализация |
---|---|
Порядок передачи аргументов | Первые два значения DWORD или меньшие аргументы, найденные в списке аргументов слева направо, передаются в регистрах ECX и EDX; все остальные аргументы передаются в стек справа налево. |
Обязанность по обслуживанию стека | Вызываемая функция извлекает аргументы из стека. |
Соглашение об оформлении имен | Знак "@" добавляется к именам как префикс. Знак "@", за которым следует количество байтов (в десятичной системе счисления) в списке параметров, добавляется к именам как суффикс. |
Соглашение о преобразовании регистра | Изменение регистра не выполняется. |
В следующих версиях компилятора могут использовать другие регистры для сохранения параметров.
Использование параметра компилятора /Gr приводит к компиляции каждой функции в модуле, так как __fastcall если функция не объявлена с помощью конфликтующего атрибута или имени функции main .
Ключевое __fastcall слово принимается и игнорируется компиляторами, предназначенными для архитектур ARM и x64; на микросхеме x64 по соглашению первые четыре аргумента передаются в регистрах, когда это возможно, и дополнительные аргументы передаются в стеке. Дополнительные сведения см. в соглашении о вызовах x64. На микросхеме ARM можно передавать в регистрах до четырех целочисленных аргументов и до восьми аргументов с плавающей запятой; дополнительные аргументы передаются в стеке.
Если используется внестрочное определение нестатической функции класса, то модификатор соглашения о вызовах не должен быть задан во внестрочном определении. То есть для нестатических методов-членов считается, что соглашение о вызовах, указанное во время объявления, было сделано в точке определения. Рассмотрим следующее определение класса:
В этом случае следующий код:
Для совместимости с предыдущими версиями _fastcall является синонимом __fastcall , если не указан параметр компилятора /Za (отключить расширения языка).
Особенности соглашения __vectorcall
__vectorcall Целочисленные аргументы функции передаются по значению с использованием до двух (в x86) или четырех (в x64) целочисленных регистров и до шести регистров XMM для значений с плавающей запятой и векторов, а остальные передаются в стеке справа налево. Вызываемая функция очищает стек до возврата управления. Возвращаемые векторные значения и значения с плавающей запятой возвращаются в XMM0.
Для языка C соглашение об именовании __vectorcall предусматривает использование имени функции с двумя символами @@ и размером аргументов функции в байтах после него. Преобразование регистра не выполняется. В качестве соглашения об именовании компилятор использует следующий шаблон:
Предварительное понимание регулярных выражений Python (4)
Сегодня я продолжу делиться базовыми знаниями о регулярных выражениях Python. В основном я представляю использование специального символа "<>". Ниже приведено конкретное руководство. .
Особенности соглашения __fastcall
Некоторые аргументы функции __fastcall передаются в регистрах (для 32-разрядных процессоров, ECX и EDX), а остальные — в стеке справа налево. Вызываемая подпрограмма извлекает аргументы из стека до возврата управления. Как правило, параметр /Gr уменьшает время выполнения.
Будьте осторожны при использовании соглашения о вызовах __fastcall для функции, написанной на встроенном языке ассемблера. Использование регистров может конфликтовать с использованием компилятора.
Для языка C соглашение об именовании __fastcall предусматривает использование имени функции с символом @ перед ним и размером аргументов функции в байтах после него. Преобразование регистра не выполняется. В качестве соглашения об именовании компилятор использует следующий шаблон:
С соглашением об именовании __fastcall следует использовать стандартные файлы включения. В противном случае вы получите неразрешенные внешние ссылки.
2. Обычно используемые звонки
7. Позвоните соглашению _CDECL, _stdcall, _fastcall
Процесс вызова функции
Чтобы глубоко понять соглашение о вызовах функций, вам необходимо понять процесс вызова функций и детали вызова.
Предположим, что функция A вызывает функцию B. Мы называем функцию A «вызывающей стороной», а функцию B - вызываемой. Как показано в следующем коде, ShowResult является вызывающим, а add - вызываемым.
Процесс вызова функции может быть описан следующим образом:
(1) Сначала поместите базовый адрес (ebp) стека вызывающего абонента (A) в стек, чтобы сохранить информацию предыдущей задачи.
(2) Затем присвойте значение указателя верхнего стека (esp) вызывающей стороны (A) для ebp в качестве нового базового адреса (то есть нижнего стека вызываемого B).
(3) Затем по этому базовому адресу (в нижней части стека вызываемого абонента B) соответствующее пространство (обычно с использованием подинструкции) используется в качестве пространства стека вызываемого абонента B.
(4) После возврата из функции B ebp текущего кадра стека восстанавливается до вершины стека вызывающей стороны A (esp), так что вершина стека восстанавливается до позиции, предшествующей вызову функции B, затем Затем вызывающая сторона A может извлечь предыдущее значение ebp с вершины восстановленного стека (это можно сделать, поскольку это значение было помещено в стек за один шаг до вызова функции). Таким образом, ebp и esp восстанавливают позицию перед вызовом функции B, то есть состояние до вызова функции восстановления стека B.
Этот процесс завершается в сборке AT & T двумя инструкциями, а именно:
__cdecl - это аббревиатура объявления C, указывающая соглашение о вызовах функций по умолчанию для C и C ++. Это соглашение о вызовах по умолчанию для C / C ++ и MFCX.
- Вставьте параметры в стек в порядке справа налево.
- Вызывающая сторона извлекает параметры из стека. Помните: стек памяти для передачи параметров поддерживается вызывающей стороной, а возвращаемое значение находится в EAX. Следовательно, эта функция должна использоваться для функций с переменными параметрами, такими как printf.
- Когда компилятор генерирует измененное имя для функции этого правила вызова во время компиляции, префикс подчеркивания добавляется к имени выходной функции в формате _function. Например, измененное имя функции int add (int a, int b) - _add.
(1). Чтобы убедиться, что параметры помещены в стек справа налево, мы можем увидеть следующий код: Отладка для одношаговой отладки, мы можем видеть, что наш стек вызовов сначала войдет в GetC (), а затем в GetB ( ) и, наконец, введите GetA ().
(2). Второй пункт - «вызывающий объект извлекает параметры из стека». Это работа компилятора, которую пока невозможно проверить. Чтобы глубже понять эту часть, вам необходимо изучить знание ассемблера.
(3). Модифицированное имя функции, это можно сделать с помощью дампа / экспорта VS скомпилированной библиотеки DLL.ProjectNameКоманда «.dll» для просмотра (будет подробно описана в последующих главах) или непосредственно откройте файл .obj, чтобы найти соответствующее имя метода (например, поиск для добавления).
С точки зрения отладки кода и программ, нам не нужно обращать слишком много внимания на порядок передачи параметров и очистки стека, потому что это определяется компилятором, и мы не можем его изменить. Но третий момент часто сбивает нас с толку, потому что, если мы не понимаем этот момент, часто возникают необъяснимые ошибки при вызове и использовании друг друга между несколькими библиотеками (такими как dll, lib, exe). Я подробно расскажу об этом в следующих главах.
__stdcall - это сокращение от Standard Call, который является стандартным методом вызова C ++. Конечно, это стандарт, определенный Microsoft. __stdcall обычно используется в Win32 API (см. определение WINAPI).
- Вставьте параметры в стек в порядке справа налево.
- Вызываемый объект извлекает параметры из стека. Помните: функция очищает стек при выходе, и возвращаемое значение находится в EAX.
- Соглашение о вызовах __stdcall добавляет префикс подчеркивания перед именем выходной функции, за которым следует символ "@" и число байтов в ее параметрах в формате _function @ number. Например, измененное имя функции int sub (int a, int b) - _sub @ 8.
Основная функция __fastcall - быстрая, потому что она передает параметры через регистры.
- Фактически, __fastcall использует ECX и EDX для передачи первых двух параметров DWORD или меньших. Остальные параметры по-прежнему передаются справа налево. Вызванная функция очищает стек памяти переданных параметров перед возвратом.
- Соглашение о вызовах __fastcall добавляет символ «@» перед именем выходной функции, за которым следует символ «@» и число байтов в ее параметрах в формате @ function @ number, например, измененное имя double multi (double a, double b) Это @ multi @ 16.
- __fastcall и __stdcall очень похожи, единственное отличие состоит в том, что первые два параметра передаются через регистр. Обратите внимание, что два параметра, передаваемые через регистр, являются слева направо, то есть первый параметр входит в ECX, второй входит в EDX, а остальные параметры передаются справа налево, и возврат по-прежнему осуществляется через EAX.
__thiscall - соглашение о вызовах по умолчанию для функций-членов класса C ++, но оно не имеет явной формы объявления. Поскольку в классе C ++ вызов функции-члена также имеет параметр указателя this, поэтому он должен обрабатываться особым образом. Характеристики соглашения о вызовах thiscall:
Эти параметры определяют порядок, в котором аргументы функции передаются в стек, то, удаляет ли вызывающая или вызываемая функция аргументы из стека в конце вызова, а также соглашение о декорировании имен, используемое компилятором для идентификации отдельных функций.
Синтаксис
/Gd
/Gr
/Gv
/Gz
5. Имя функции под разными вызовами
Использование внутреннего соединения, левого соединения, правого соединения в оракуле
Левое-правое соединение фактически говорит, какая таблица является результатом нашего совместного запроса ~ 1. Взаимосвязь проста select A.*, B.* from A,B where A.id = B.id select A.*, B.* from.
Интеллектуальная рекомендация
6. Общие вопросы, вызванные призвающими конвенциями
Если соглашение о определении несовместимо, он приведет к уничтожению стека, что приведет к двум распространенным проблемам:
1) Функция Prototype Декларация и функциональные определения несовместимы
2) Различные функции объявлены, когда функция импорта DLL, такая как использование конвенции по умолчанию _CDECL, когда DLL экспортирует, однако при использовании файла DLL во внешнем проекте, из-за использования модификаций WinAPI через API Win32, стек разрушен Отказ
[Код очень подробный] POJ 2492 A Bug's Life (и проверьте коллекцию)
1. Описание заголовка 2. Инструкции по анализу алгоритмов и руководство по написанию кода. Похожие темы:POJ 1182 Решение проблемы пищевой цепи Наблюдается m насекомых и n вязок. Насекомые u и v могут .
4. Несколько обычно используемых звонков
1) _CDECL Соглашение
_CDECL Call Consentions, также известный как C CONT CONSTORTS, является соглашение о вызове по умолчанию языка C / C ++. Параметр справа налево Манера находится в стеке, сама функция не очищает стек, эта работа отвечает вызывающим абонентом, возвращаемое значение находится в EAX. Поскольку укладок очищается вызывающим абонентом, наличие вариабельных параметров разрешено, например, int sprintf (char * buffer, const char * format, . )
2) конвенции _stdcall
_Stcall много раз, называется Pascal звонки. Язык Паскаль является очень распространенным преподавательным компьютерным программированием языком программирования, и его грамматика строгое. Параметр справа налево Способ, сама функция очищает стек, вернуть значение в EAX
3) _fastcall согласился
Как следует из названия, _fastcall функционирует быстры, потому что он передает параметры через регистр процессора. Он передает первые два двойных слова (DWORD) или меньших параметров с ECX и EDX, а остальные параметры следуют справа налево Способ, сама функция очищает стек, вернуть значение в EAX
4) _Thiscall согласился
В это время язык C ++ уникален для схемы вызова для вызова функции классов элементов. Если параметр определен, этот указатель хранится в регистре ECX, сама функция очищает стек; если параметр неопределен, этот указатель вводится после того, как все параметры введены в стек, а вызывающий абонент куча. _Thiscall не является ключевым словом, программист не может быть использован. Параметр справа налево Способ попасть в стек
Установка данного параметра компилятора в среде разработки Visual Studio
Выберите страницу свойств свойства конфигурации>C/C++>Дополнительно .
__cdecl — это соглашение о вызовах по умолчанию для программ C и C++. Так как вызывающий стек очищается, он может выполнять vararg функции. Соглашение __cdecl о вызовах создает более крупные исполняемые файлы, чем __stdcall, так как для каждого вызова функции требуется включить код очистки стека. В следующем списке показана реализация этого соглашения о вызовах. Модификатор __cdecl зависит от корпорации Майкрософт.
Элемент | Реализация |
---|---|
Порядок передачи аргументов | Справа налево. |
Обязанность по обслуживанию стека | Вызывающая функция выводит аргументы из стека. |
Соглашение об оформлении имен | Перед именами ставится символ подчеркивания (_), кроме случаев экспорта функций __cdecl, использующих компоновку С. |
Соглашение о преобразовании регистра | Изменение регистра не выполняется. |
Дополнительные сведения см. в разделе "Декорированные имена".
Поместите модификатор __cdecl перед переменной или именем функции. Так как соглашения об именовании и вызовах C используются по умолчанию, единственный раз __cdecl , когда вы указали /Gv параметр компилятора (vectorcall), /Gz или (fastcall) в /Gr коде x86. Параметр компилятора /Gd принудительно применяет соглашение о вызовах __cdecl .
В процессорах ARM и x64 принимается, __cdecl но обычно игнорируется компилятором. По соглашению на ARM и x64 аргументы передаются в регистрах, когда это возможно, а последующие аргументы передаются в стек. В коде x64 используется __cdecl для переопределения параметра компилятора /Gv и использования соглашения о вызовах x64 по умолчанию.
Если используется внестрочное определение нестатической функции класса, то модификатор соглашения о вызовах не должен быть задан во внестрочном определении. То есть для нестатических методов-членов считается, что соглашение о вызовах, указанное во время объявления, было сделано в точке определения. Рассмотрим следующее определение класса:
В этом случае следующий код:
Для совместимости с предыдущими версиями cdecl и _cdecl являются синонимом, __cdecl если не указан параметр компилятора /Za (отключить расширения языка).
Читайте также: