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

Вчера я обнаружил, что пишу код следующим образом:

SomeStruct getSomeStruct()
{
    SomeStruct input;

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

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

0

6 ответы

For me the compiler didn't allow it: http://codepad.org/KkzVCesh

0
добавлено
Похоже, что это не позволило, потому что у вас настроен ваш компилятор, чтобы предупреждения были обработаны как ошибки. Считаете ли вы, что это может быть случай, когда у меня слишком низкий уровень предупреждения?
добавлено автор Jason Baker, источник

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

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

0
добавлено
Я всегда удивлялся, что это всего лишь предупреждение, а не ошибка. Болит гораздо чаще, чем помогает.
добавлено автор Jim Buck, источник
В частности, если я забуду вернуть std :: vector или другой объект, который управляет некоторой кучной памятью, объект будет оставлен в недопустимом состоянии, и поэтому он не будет знать, как уничтожить себя, когда пришло время. Это делает сложную сессию отладки.
добавлено автор Bernard, источник
Было законно не возвращать что-либо в C. Оно все еще не определено, но, по крайней мере, оно было законным.
добавлено автор Jonathan, источник

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

  • Microsoft VC, all versions (since VC6 anyway):

    error C4716: 'getSomeStruct' : must return a value

  • Digital Mars:

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

  • Comeau:

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

  • gcc:

    no error or warning

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

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

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

0
добавлено
Я возражаю против утверждения, что GCC не предупреждает об этом. Запустите gcc с помощью опции -Wall , и вы получите: предупреждение: нет оператора return в функции, возвращающей не-void [-Wreturn-type]
добавлено автор Loomchild, источник

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

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

0
добавлено

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

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

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

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

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

0
добавлено

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

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

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

0
добавлено
pro.cxx
pro.cxx
3 049 участник(ов)

C/C++ chat 0. Простые вопросы, лабы и о IDE — в чат новичков @supapro 1. Не хамим, не переходим на личности, не вбрасываем утверждения без доказательств 2. No Ads, offtop, flood Объявления о вакансиях и евенты - в лс @AlexFails https://t.me/ProCxx/259155

supapro.cxx
supapro.cxx
1 925 участник(ов)

Чат для тех, кто немного знает C++, простые вопросы по реализации, синтаксису и ide – сюда, а для другого есть: /Главный чат по серьезным вопросам — @ProCxx /Чат по обсуждению всего — @fludpac

C++ Russia
C++ Russia
384 участник(ов)

Сообщество разработчиков C++ в Telegram.

cxx.Дискуссионная
cxx.Дискуссионная
298 участник(ов)

это не двач, общайтесь вежливо; разговор на почти любые темы; Не согласны с баном? В лс @AlexFails, @ivario

C++ для маленьких и тупых
C++ для маленьких и тупых
105 участник(ов)

Лоу левел (по среднему IQ участников) чатик ExtremeCode @extremecode Флудилка @extremecode_rest