Что такое пользовательские соглашения о вызовах?
Что это? И как они влияют на меня как на разработчика?
по теме:
каковы различные соглашения о вызовах в C/C++ и что каждый означает?
4 ответов
A вызов описывает, как что-то может вызывать другую функцию. Это требует, чтобы параметры и состояние передавались другой функции, чтобы она могла правильно выполнять и возвращать управление. Способ, которым это делается, должен быть стандартизирован и указан, чтобы компилятор знал, как упорядочивать параметры для потребления вызываемой удаленной функцией. Существует несколько стандартных соглашений о вызовах, но наиболее распространенными являются fastcall
, stdcall
и cdecl
.
как правило, термин пользовательское соглашение о вызовах это немного неправильно и относится к одной из двух вещей:
нестандартное соглашение о вызовах или то, которое не широко используется (например, если вы строите архитектуру с нуля).
специальные оптимизация, которую может выполнить компилятор/компоновщик, использующий одноразовое соглашение о вызовах с целью повышения производительности.
в последнем случае это приводит к тому, что некоторые значения, которые в противном случае были бы помещены в стек, будут храниться в регистрах. Компилятор попытается принять это решение на основе того, как параметры используются внутри кода. Например, если параметр будет использоваться в качестве максимального значения для индекса цикла, то индекс сравнивается с max на каждой итерации, чтобы увидеть, должны ли вещи продолжаться, что было бы хорошим случаем для перемещения его в регистр.
если оптимизация выполняется, это обычно уменьшает размер кода и повышает производительность.
и как они влияют на меня как на разработчика?
С вашей точки зрения как разработчика, вам, вероятно, все равно; это оптимизация, которая произойдет автоматически.
каждый язык при вызове функции имеет соглашение о том, какие параметры будут переданы в переменных регистра vs в стеке и как будут возвращены возвращаемые значения.
иногда используется другое соглашение, чем стандартное, и это называется пользовательским соглашением о вызовах.
Это наиболее распространено при взаимодействии между различными языками. Например, C и Pascal имеют разные соглашения о том, как передавать параметры. От C с точки зрения, соглашение о вызове Pascal можно было бы назвать пользовательским соглашением о вызове.
Я не думаю, что вам действительно нужно заботиться.
обычные соглашения о вызовах-это такие вещи, как __stdcall и __fastcall. Они определяют, как ваша подпись вызова преобразуется в макет стека, кто (вызывающий или вызываемый) отвечает за сохранение и восстановление регистров и т. д. Например, __fastcall должен использовать больше регистров, где __stdcall будет использовать больше стека.
пользовательские соглашения о вызовах оптимизированы специально для конкретной функции и как они используются. Они происходят только, IIRC, для функций, которые являются локальными для определенного модуля. Вот как компилятор знает так много о том, как он используется, а также как вы знаете, что никакой внешний вызывающий объект не должен иметь возможность указать соглашение.
исходя из этого, ваш компилятор будет использовать их автоматически, когда это необходимо, ваш код будет работать немного быстрее и/или займет немного меньше места, но вам не нужно беспокоиться об этом.
Если вы непосредственно не манипулируете стеком или не пишете встроенную сборку, ссылающуюся на локальные переменные, это не влияет на вас. Или если ваше взаимодействие с библиотеками связано с различными соглашениями о вызовах
Что это такое: большинство компиляторов и таких используют стандартное соглашение о вызовах, такое как cdecl, где аргументы функции передаются в определенном порядке в стек и т. д.