Почему нет ошибки компилятора для main () без возврата в конце? - PullRequest
9 голосов
/ 30 января 2009

Я работаю над тизером C-brain: напишите стандартную программу Hello-World без точек с запятой.

Мой лучший ответ на данный момент:

int main(void)
{
    if (printf("Hello World!\n"), exit(0), 0)
    {
        /* do nothing */
    }
}

Но я не понимаю, почему я не получаю ошибку компилятора (Visual Studio):

error C4716: 'main' : must return a value

Я пробовал другие функции с объявленным типом возврата, но пропустил оператор return, и получил эту ошибку компилятора.


Обратите внимание, что я тоже пробовал:

int foo(void)
{
    if (printf("Hello World!\n"), exit(0), true)
    {
        /* do nothing */
    }
}

int main(void)
{
    foo();
}

И не получите ошибку компилятора на foo. Если я удаляю «exit (0)», я do получаю ошибку компилятора. Видимо компилятор знает, что «выход» - это специальная функция? Это кажется мне очень странным.

Ответы [ 6 ]

9 голосов
/ 30 января 2009

Как отметил Дженс в комментарии, опубликованный код не проявляет неопределенного поведения. Первоначальный ответ здесь не верен и, похоже, на самом деле даже не отвечает на вопрос (перечитывая все через несколько лет).

Вопрос можно сформулировать так: «Почему MSVC не выдает предупреждение C4716 для main() при тех же обстоятельствах, что и для других функций»?

Обратите внимание, что диагностика C4716 является предупреждением, а не ошибкой. Что касается языка Си (в любом случае, с точки зрения стандартов), то нет необходимости диагностировать отсутствие ошибок. но это на самом деле не объясняет, почему есть разница, это просто техническая специфика, которая может означать, что вы не можете жаловаться слишком много ...

Реальное объяснение того, почему MSVC не выдает предупреждение для main(), когда это происходит для других функций, действительно может ответить только кто-то из команды MSVC. Насколько я могу судить, документы не объясняют разницу, но, возможно, я что-то упустил; так что все, что я могу сделать, это спекулировать:

В C ++ функция main() обрабатывается специально в том смысле, что перед закрывающей скобкой есть неявный return 0;.

Я подозреваю, что компилятор Microsoft C обеспечивает такую ​​же обработку при компиляции в режиме C (если вы посмотрите на код сборки, регистр EAX очищается, даже если нет return 0;), поэтому в том, что касается компилятора нет причин выдавать предупреждение C4716. Обратите внимание, что режим Microsoft C совместим с C90, а не с C99. В C90 «бег в конец» main() имеет неопределенное поведение. Однако всегда возвращаемый 0 соответствует низким требованиям неопределенного поведения, поэтому проблем нет.

Таким образом, даже если бы программа в вопросе не выполнила до конца main() (что привело к неопределенному поведению), все равно не было бы предупреждения.


Оригинальный, не очень хороший ответ:

В ANSI / ISO 90 C это неопределенное поведение, поэтому MS действительно должна выдавать ошибку (но это не требуется стандартом). В C99 стандарт допускает подразумеваемый return в конце main () - как и в C ++.

Так что, если это скомпилировано как C ++ или C99, ошибки нет, и это то же самое, что и return 0;. C90 приводит к неопределенному поведению (которое не требует диагностики).

Интересно (ну, может быть, и нет), из нескольких компиляторов (VC9, VC6, GCC 3.4.5, Digital Mars, Comeau) Я попробовал это с моими базовыми, в основном, настройками по умолчанию (среда, которую я почти всегда использую для быстрого и детального тестирования фрагментов кода) единственный компилятор, который предупреждает об отсутствующем операторе возврата, - это VC6 при компиляции в виде программы на C ++ (VC6 не жалуется при компиляции для C).

Большинство компиляторов жалуются (предупреждение или ошибка), если функция не названа main. Digital Mars при компиляции для C не делает, а GCC не для C или C ++.

6 голосов
/ 30 января 2009

если вы ничего не вернете, программа вернет 0. Смотри http://www.research.att.com/~bs/bs_faq2.html#void-main

2 голосов
/ 30 января 2009

Компиляция может быть достаточно умной, чтобы знать, что вызывается exit (0), который никогда не возвращается, поэтому он не нужен.

1 голос
/ 12 мая 2012

Не возвращаться из main или, точнее говоря, не достигать завершающего '}' основной функции, вполне нормально по разным причинам. Типичные случаи включают в себя зацикливание навсегда и выход или прерывание раньше.

В этом случае exit(0) гарантированно будет выполнено до достижения конца основного. Почему компилятор должен предупреждать? Вы не ожидаете предупреждения для них, не так ли?

int main (void) { for (;;) { /* do something useful */ } }

int main (void) { /* do something  */; exit (0); }

Я бы даже удивился, если бы

int main (void)
{
    if (printf("Hello World!\n"), exit(0), true)
    {
        /* do nothing */
    }
    return 0;
}

не вызовет warning: unreachable code: return 0 или что-то подобное.

1 голос
/ 30 января 2009

С http://msdn.microsoft.com/en-us/library/k9dcesdd(VS.71).aspx

Справочник по языку C ++

Функция выхода

Функция выхода, объявленная в стандартный включаемый файл STDLIB.H, завершает программу на C ++.

Значение, указанное в качестве аргумента для выход возвращается в действующий система в качестве кода возврата программы или код выхода По договоренности, возврат Код ноль означает, что программа завершено успешно.

Примечание. Вы можете использовать константы EXIT_FAILURE и EXIT_SUCCESS, определенные в STDLIB.H, чтобы указать успех или сбой вашей программы.

Выдача ответное заявление от основного Функция эквивалентна вызову функция выхода с возвращаемым значением как его аргумент.


1 голос
/ 30 января 2009

Потому что это не ошибка - это неопределенное поведение. См. Раздел 6.9.1, пункт 12 стандарта C99:

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

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

main() специально для C: это единственная функция, которая не может возвращать значение. Стандарт C говорит, что если управление достигает конца main() без оператора return, оно неявно возвращает 0. Это верно только для main(), все другие функции, не являющиеся пустыми, должны возвращать значение.

Раздел 5.1.2.2.3:

Если тип возвращаемой функции main является типом, совместимым с int, возвращаемое значение из начальный вызов основной функции эквивалентен вызову функции выхода со значением, возвращаемым основной функцией в качестве аргумента; 10) достижением}, который завершает Функция main возвращает значение 0. Если тип возвращаемого значения не совместим с int, состояние завершения, возвращаемое в хост-среду, не указано.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...