Неявное int возвращаемое значение функции C

Я гуглил и просто не могу найти ответ на этот простой вопрос.

Работая над устаревшей кодовой базой (недавно портированной на Linux и медленно обновляющейся до нового компилятора), и я вижу много

int myfunction(...)
{
// no return...
}

Я знаю, что неявный возврат TYPE функции является int, но что такое неявное возвращаемое значение VALUE, когда не указан возврат. Я проверил и получил 0, но это только с gcc. Этот компилятор специфичен или стандартно равен 0?

РЕДАКТИРОВАТЬ: 12/2017 Скорректированный принятый ответ основан на том, что он ссылается на более свежую версию стандарта.

7 ответов

Решение

Такое возможно, но только при условии, что возвращаемое значение функции никогда не используется. Стандарт C11 говорит в пункте 6.9.1:

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

(AFAIR предыдущая версия стандарта имела похожую формулировку)

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

От стандарта 89 года, как указано в новом завете:

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

Этот стандарт обычно выражает практическое поведение уже существующих реализаций.

Оператор return никогда не является обязательным в конце функции, даже если тип возвращаемой функции не является void, Диагностика не требуется, и это не неопределенное поведение.

Пример (определенное поведение):

int foo(void)
{
}

int main()
{
    foo();
}

Но читая возвращаемое значение foo является неопределенным поведением:

int bla = foo();  // undefined behavior

Из стандарта С:

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

main Функция является исключением из этого правила, как будто } достигается в main это эквивалентно, как если бы return 0; заявление.

Это просто неопределенное поведение; если вы не заполняете область возврата (например, обычно это eax/rax на процессорах семейства x86), в последнем случае значение будет настроено через некоторый побочный эффект в вашей функции.

См. Является ли оператор return обязательным для функций C++, которые не возвращают void? который является в основном дубликатом этого вопроса (за исключением того, что он помечен как C++).

Если return операторы последовательно не возвращают значение, функцию лучше всего преобразовать в и объявить как возвращающую void:

void myfunction(...)
{
    ...
    return;
    ...
}

Если есть некоторые return expr; и немного return; операторы в функции, то вам нужно решить, какое поведение лучше, и сделать их согласованными - либо всегда возвращать значение и оставлять тип как int или никогда не возвращать значение и изменить тип на void,

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

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

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

Я уверен, что это неопределенное поведение для функции, тип возвращаемого значения не void опустить return заявление. В C99 есть исключение для mainгде, если return оператор не указан, предполагается, что он возвращает 0 неявно, но это не относится ни к какой другой функции.

Он может работать на определенной комбинации платформы / компилятора, но вы никогда не должны полагаться на такие особенности. Использование любого неопределенного поведения в вашем коде делает его непереносимым. Однако часто встречается неопределенное поведение в устаревшем коде.

Другие вопросы по тегам