Что произойдет, если вы не вернете значение в C++?

StackOverflow https://stackoverflow.com/questions/293499

  •  08-07-2019
  •  | 
  •  

Вопрос

Вчера я обнаружил, что пишу такой код:

SomeStruct getSomeStruct()
{
    SomeStruct input;

    cin >> input.x;
    cin >> input.y;
}

Конечно, я забыл вернуть только что созданную структуру.Как ни странно, значения в структуре, которая был возвращаемый этой функцией, инициализируется нулем (то есть при компиляции с использованием g++).Это просто совпадение или где-то неявно был создан и инициализирован другой SomeStruct?

Это было полезно?

Решение

  

Был ли другой SomeStruct создан и инициализирован где-то неявно?

Подумайте, как возвращается структура. Если и x , и y являются 32-битными, это слишком большой размер для регистра в 32-битной архитектуре, и то же самое относится к 64-битным значениям в 64-битная архитектура (в ответе @Denton Gentry упоминается, как возвращаются более простые значения), поэтому его нужно где-то размещать. Для этого было бы расточительно использовать кучу, поэтому она должна быть размещена в стеке. Но он не может быть в фрейме стека вашей функции getSomeStruct , поскольку он больше не действителен после возврата из функции.

Вместо этого компилятор заставляет вызывающую функцию сообщать вызываемой функции, куда поместить результат (который, вероятно, находится где-то в стеке вызывающей стороны), передавая вызываемой функции скрытый указатель на выделенное ей пространство. Таким образом, место, где он устанавливается на ноль, находится в вызывающей стороне , а не в вашей функции getSomeStruct .

Существуют также оптимизации, такие как " оптимизация возврата именованных значений " где могут быть выбраны дополнительные копии. Таким образом, если бы вы использовали отсутствующий return , результат был бы создан непосредственно на месте, выделенном вызывающей стороной, вместо создания временного и его копирования.

Чтобы узнать больше о том, что происходит, вы должны взглянуть на функцию вызывающего абонента. Инициализирует ли он (до нуля) «пустой» код? SomeStruct , которому вы позже назначите возвращаемое значение вашей функции getSomeStruct ? Или это делает что-то еще?

Другие советы

Падение конца функции, объявленной для возврата значения (без явного возврата значения), приводит к неопределенным последствиям. Для gcc вы должны начать с переключателя командной строки -Wall , который включает большинство полезных предупреждений. Конкретное предупреждение gcc, управляющее требуемым предупреждением, - это -Wreturn-type (которое включено в -Wall , я просто упомяну это для полноты).

После включения предупреждений следует также использовать -Werror , чтобы обрабатывать предупреждения как ошибки и останавливать сборку в тот момент, когда обнаруживается ошибка.

Соглашения о вызовах для большинства современных архитектур ЦП указывают конкретный регистр для передачи возвращаемого значения функции вызывающей стороне. Вызывающая сторона выполняет вызов функции, а затем использует указанный регистр в качестве возвращаемого значения. Если вы явно не вернете значение, вызывающая сторона, тем не менее, будет использовать любой мусор в этом регистре.

Компилятор также будет использовать все регистры, которые он имеет для внутренних вычислений внутри функции. Регистр, предназначенный для хранения возвращаемого значения, также будет использоваться для вычисления misc внутри функции. Таким образом, когда вы забываете указать возвращаемое значение, нет ничего необычного в том, что правильное значение чудесным образом возвращается вызывающей стороне: компилятор использовал этот регистр для хранения вашего объекта.

К сожалению, даже тривиальное изменение функции может привести к изменению распределения регистров, поэтому возвращаемое значение становится истинным мусором.

Я нахожу это интересным.При использовании параметров по умолчанию следующие компиляторы ведут себя следующим образом при компиляции: GetSomeStruct() функция:

  • Microsoft VC, все версии (во всяком случае, начиная с VC6):

    error C4716: 'getSomeStruct' : must return a value

  • Цифровой Марс:

    Warning 18: implied return of getSomeStruct at closing '}' does not return value

  • Комо:

    warning: missing return statement at end of non-void function "getSomeStruct"

  • ГЦК:

    нет ошибок или предупреждений

Учитывая следующие пару предложений из стандарта (6.6.3 Параграф 2):

Оператор возврата без выражения может использоваться только в функциях, которые не возвращают значение, то есть функция с void типа возврата, конструктора (12.1) или деструктора (12.4)....Выход с конца функции эквивалентен возврату без значения;Это приводит к неопределенному поведению в функции возврата значений.

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

Для меня компилятор этого не допустил: http://codepad.org/KkzVCesh

Вы не получили никакого предупреждения, потому что у вас не было включено -Wall -Werror . (Как указано в других ответах)

Однако я думаю, что вы, вероятно, получили заполненную нулями структуру в результате, потому что объект стека был создан по умолчанию в функции вызывающей стороны, возможно, с явными нулевыми аргументами или из-за нулей в стеке?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top