Как функции С++ возвращают большой объект или структуру?
Я прочитал в Computer Systems перспективу программиста, что при программировании в ассемблере в соглашении относительно протокола вызывающего абонента указано, что возвращаемое значение функции должны храниться в регистре eax
(или аналоговом rax
, в 64-битном компьютере).
Я предполагаю, что это то, что автоматически происходит "за кулисами" при программировании на C, то есть компилятор C "знает", чтобы использовать регистр eax
для возвращаемых значений функций.
Но что происходит в С++, когда возвращаемое значение является большим объектом, который не вписывается в 32-разрядный регистр eax
или 64-бит rax
? Очевидно, вы не можете передать это с помощью стека, так как компилятор обрабатывает операцию возврата по значению большого объекта?
Не обращайте внимания на большой объект, как компилятор C обрабатывает возвращаемую стоимость большой структуры?
Сохраняет ли он его во временном пространстве памяти и возвращает его адрес как возвращаемое значение? Если это так, он должен предсказать, сколько вызовов нужно делать с функцией во время выполнения, а иногда это невозможно, не так ли?
Ответы
Ответ 1
Очевидно, вы не можете передать это с помощью стека...
Собственно, теория состоит в том, что всякий раз, когда функция вызывается и ее фрейм стека размещается, он также создает пространство для возвращаемого объекта. Это зависит от вызывающей функции, чтобы гарантировать, что это возвращаемое значение будет скопировано где-то в пределах своего собственного стекового кадра, чтобы оно могло удерживать его.
Это напрямую соответствует тому, как он работает на C и С++. У вас есть оператор return ...;
, который копирует некоторое значение в возвращаемый объект. Возвращаемый объект является временным объектом, поэтому вызывающий код должен его хранить где-то с чем-то вроде int value = foo();
.
Однако практически не нужно даже беспокоиться о резервировании пространства для возвращаемого значения. Вместо этого вызывающая функция освобождает место для нее, и вызываемая функция устанавливает прямое значение возвращаемого значения. Именно то, что возвращает значение оптимизации, и то, что представляет собой копия.
Ответ 2
Очевидно, вы не можете передать это, используя стек
Вы можете! Хитрость заключается в том, чтобы вызывающий абонент выделил пространство в стеке, и пусть функция заполнит его.
По существу, функция возвращает данные в части вызывающего элемента кадра стека.
Ответ 3
Вы должны представить, что возвращаемое значение функции переходит в стек, подобно локальной переменной. И, подобно локальным переменным, это может быть оптимизировано (и существуют соглашения в зависимости от архитектуры, которые определяют четко определенное поведение), так что небольшие возвращаемые значения попадают в регистры вместо стека.