С тех пор, как я понял много лет назад, что это не приводит к ошибке по умолчанию (по крайней мере, в GCC), я всегда задавался вопросом, почему?
Я понимаю, что вы можете использовать флаги компилятора для выдачи предупреждения, но не должно ли это быть ошибкой? Почему имеет смысл, чтобы не пустая функция не возвращала значение, чтобы быть действительным?
Пример в соответствии с просьбой в комментариях:
#include <stdio.h>
int stringSize()
{
}
int main()
{
char cstring[5];
printf( "the last char is: %c\n", cstring[stringSize()-1] );
return 0;
}
... компилирует.
-Werror=return-type
будет рассматривать только это предупреждение как ошибку. Я просто проигнорировал предупреждение, и пара минут разочарования, выслеживающих неверныйthis
указатель, привели меня сюда и к такому выводу.std::optional
функции без возврата возвращает «истинное» необязательное значениеОтветы:
Стандарты C99 и C ++ не требуют, чтобы функции возвращали значение. Отсутствующий оператор возврата в функции, возвращающей значение, будет определен (возвращаться
0
) только вmain
функции.Обоснование состоит в том, что проверить, возвращает ли каждый путь кода значение, довольно сложно, и возвращаемое значение может быть установлено с помощью встроенного ассемблера или других хитрых методов.
Из C ++ 11 черновик:
§ 6.6.3 / 2
§ 3.6.1 / 5
Обратите внимание, что поведение, описанное в C ++ 6.6.3 / 2, отличается от поведения в C.
gcc выдаст вам предупреждение, если вы вызовете его с опцией -Wreturn-type.
Просто для любопытства посмотрите, что делает этот код:
Этот код имеет формально неопределенное поведение, и на практике он вызывает соглашение и архитектуру . В одной конкретной системе с одним конкретным компилятором возвращаемое значение является результатом последней оценки выражения, сохраненной в
eax
регистре процессора этой системы.источник
throw
илиlongjmp
, должен ли компилятор требовать недоступностьreturn
после вызова невозвратной функции? Случай, когда он не нужен, не очень распространен, и требование включить его даже в таких случаях, вероятно, не было бы обременительным, но решение не требовать его является разумным.По умолчанию gcc не проверяет, что все пути кода возвращают значение, потому что в общем случае это невозможно. Предполагается, что вы знаете, что делаете. Рассмотрим общий пример с использованием перечислений:
Вы, программист, знаете, что, за исключением ошибки, этот метод всегда возвращает цвет. gcc верит, что вы знаете, что делаете, поэтому не заставляет вас помещать возврат в конец функции.
javac, с другой стороны, пытается проверить, что все пути кода возвращают значение, и выдает ошибку, если не может доказать, что все они делают. Эта ошибка предписана спецификацией языка Java. Обратите внимание, что иногда это неправильно, и вы должны добавить ненужный оператор возврата.
Это философская разница. C и C ++ являются более разрешающими и доверчивыми языками, чем Java или C #, поэтому некоторые ошибки в более новых языках являются предупреждениями в C / C ++, а некоторые предупреждения игнорируются или отключаются по умолчанию.
источник
System.exit()
никогда не вернется.System.exit()
никогда не вернется. Я посмотрел его ( java.sun.com/j2se/1.4.2/docs/api/java/lang/… ), и в документах просто говорится, что он "никогда не возвращается". Интересно, что это значит ...Вы имеете в виду, почему утечка из конца функции, возвращающей значение (т.е. выход без явного
return
) не является ошибкой?Во-первых, в C вопрос о том, возвращает ли функция что-либо значимое или нет, имеет значение только в том случае, если исполняемый код фактически использует возвращаемое значение. Возможно, язык не хотел заставлять вас возвращать что-либо, когда вы знаете, что вы не собираетесь его использовать в большинстве случаев.
Во-вторых, очевидно, языковая спецификация не хотела заставлять авторов компилятора обнаруживать и проверять все возможные пути управления на наличие явного
return
(хотя во многих случаях это не так сложно сделать). Кроме того, некоторые пути управления могут привести к невозвратным функциям - черта, которая обычно не известна компилятору. Такие пути могут стать источником досадных ложных срабатываний.Также обратите внимание, что C и C ++ различаются в своих определениях поведения в этом случае. В C ++ просто выход из конца функции, возвращающей значение, всегда является неопределенным поведением (независимо от того, используется ли результат функции вызывающим кодом). В C это вызывает неопределенное поведение, только если вызывающий код пытается использовать возвращаемое значение.
источник
return
операторы в концеmain()
?main
особенный в этом отношении.Под C / C ++ разрешено не возвращаться из функции, которая утверждает, что что-то возвращает. Существует ряд вариантов использования, таких как вызов
exit(-1)
или функция, которая вызывает его или выдает исключение.Компилятор не собирается отказываться от легального C ++, даже если он ведет к UB, если вы просите об этом. В частности, вы просите об отсутствии предупреждений . (Gcc по-прежнему включает некоторые по умолчанию, но когда они добавляются, они, похоже, соответствуют новым функциям, а не новым предупреждениям для старых функций)
Изменение по умолчанию no-arg gcc для выдачи некоторых предупреждений может быть серьезным изменением для существующих скриптов или систем. Хорошо продуманные или
-Wall
имеют дело с предупреждениями, или переключают отдельные предупреждения.Обучение использованию цепочки инструментов C ++ является препятствием для обучения программированию на C ++, но цепочки инструментов C ++ обычно пишутся экспертами и для них.
источник
Makefile
у меня это работает-Wall -Wpedantic -Werror
, но это был одноразовый тестовый скрипт, которому я забыл предоставить аргументы.-Wduplicated-cond
участие в-Wall
загрузке GCC сломалось. Некоторые предупреждения, которые кажутся подходящими в большинстве кодов, не подходят для всего кода. Вот почему они не включены по умолчанию.int foo() { exit(-1); }
не возвращаетсяint
из функции, которая "утверждает, что возвращает int". Это законно в C ++. Теперь он не возвращает ничего ; конец этой функции никогда не достигается. На самом деле достижение концаfoo
было бы неопределенным поведением. Игнорирует случаи завершения процесса,int foo() { throw 3.14; }
также утверждает, что возвращается,int
но никогда не делает.void* foo(void* arg) { pthread_exit(NULL); }
это хорошо по той же причине (когда он используется только черезpthread_create(...,...,foo,...);
)Я считаю, что это из-за унаследованного кода (C никогда не требовал оператора return, как и C ++). Вероятно, существует огромная кодовая база, опирающаяся на эту «функцию». Но по крайней мере есть
-Werror=return-type
флаг на многих компиляторах (включая gcc и clang).источник
В некоторых ограниченных и редких случаях может оказаться полезным вытекание из конца непустой функции без возврата значения. Как следующий код, специфичный для MSVC:
Эта функция возвращает пи с использованием сборки x86. В отличие от сборки в GCC, я не знаю способа использовать
return
это, не задействуя в результате издержки.Насколько я знаю, основные компиляторы C ++ должны выдавать как минимум предупреждения для явно некорректного кода. Если я сделаю тело
pi()
пустым, GCC / Clang сообщит о предупреждении, а MSVC сообщит об ошибке.Люди упоминали об исключениях и
exit
в некоторых ответах. Это не веские причины. Вызов исключения или вызов неexit
приведут к потере выполнения функции. И компиляторы знают это: написание оператора throw или обращения к пустому телу остановит все предупреждения или ошибки от компилятора.exit
pi()
источник
void
функции после того, как встроенный asm оставляет значение в регистре возвращаемого значения. (x87st0
в данном случае EAX для целого числа. И, возможно, xmm0 в соглашении о вызовах, которое возвращает float / double в xmm0 вместо st0). Определение этого поведения специфично для MSVC; даже не лгать с-fasm-blocks
поддержкой того же синтаксиса делает это безопасным. Смотрите ли __asm {}; вернуть значение eax?При каких обстоятельствах это не приводит к ошибке? Если он объявляет тип возвращаемого значения и ничего не возвращает, для меня это звучит как ошибка.
Единственное исключение, о котором я могу подумать, - это
main()
функция, которая вообще не нуждается вreturn
выражении (по крайней мере, в C ++; у меня нет под рукой ни одного из стандартов C). Если нет возврата, он будет действовать так, как будтоreturn 0;
это последнее утверждение.источник
main()
нуженreturn
в C.return <value>;
заявленияreturn 0;
в концеmain()
(иmain()
только). Но это хороший стиль, чтобы добавить вreturn 0;
любом случае.Похоже, вам нужно включить предупреждения вашего компилятора:
источник
return;
в функции, не являющейся void, и нарушением ограничения, которое следует использоватьreturn <value>;
в функции void. Но это, я считаю, не тема. OP, как я понял, предназначен для выхода из не пустой функции безreturn
(просто позволяя элементу управления выходить из конца функции). Это не нарушение ограничений, AFAIK. Стандарт просто говорит, что это всегда UB в C ++ и иногда UB в C.Это нарушение ограничений в c99, но не в c89. Контраст:
c89:
c99:
Даже в
--std=c99
режиме gcc выдаст только предупреждение (хотя без необходимости включать дополнительные-W
флаги, как требуется по умолчанию или в c89 / 90).Отредактируйте, чтобы добавить это в c89, «достижение того,
}
что завершает функцию, эквивалентно выполнениюreturn
оператора без выражения» (3.6.6.4). Однако в c99 поведение не определено (6.9.1).источник
return
утверждений. Это не покрывает падение функции без возврата значения.