Функция C, определенная как int, но не имеющая оператора return в теле, все еще компилируется

Скажем, у вас есть код C, подобный этому:

#include <stdio.h>

int main(){
    printf("Hello, world!\n");
    printf("%d\n", f());    
}

int f(){

}

Он компилируется отлично с помощью gcc, а выход (в моей системе):

Привет, мир!

14

Но.. но.. как это возможно? Я думал, что C не позволит вам скомпилировать что-то подобное, потому что f() не имеет оператора return, возвращающего целое число. Почему это разрешено? Это функция C или компилятор, и откуда взялось 14?

Ответ 1

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

В этом случае значение 14 является возвращаемым значением из printf.

Ответ 2

скомпилируйте с помощью -Wall, чтобы включить проверку компилятора в систему.

gcc -Wall /tmp/a.c
/tmp/a.c: In function ‘main’:
/tmp/a.c:5: warning: implicit declaration of function ‘f’
/tmp/a.c:6: warning: control reaches end of non-void function
/tmp/a.c: In function ‘f’:
/tmp/a.c:10: warning: control reaches end of non-void function

Обратите внимание на то, как он выражает недостающие операторы return - поскольку "управление достигает конца не-void функции"?

Всегда компилируйте с использованием -Wall или аналогичного - вы сэкономите свою сердечную боль позже.


Я могу вспомнить несколько случаев, когда эта точная проблема заставила часы или дни отладки исправляться - она ​​сортируется до тех пор, пока она не пройдет один день.

Ответ 3

14 - это точно возвращаемое значение первого printf. Вероятно, компилятор оптимизировал вызов функции f(), а затем мы оставили 14 на EAX.

Попробуйте выполнить компиляцию кода с разными уровнями оптимизации (-O0, -O1, -O2, -O3, -Os) и посмотрите, изменяется ли выход.

Ответ 4

18 - это возвращаемое значение первого оператора печати. (количество напечатанных символов)

Это значение сохраняется в памяти стека.

Во второй функции printf значение стека "возвращается" функцией f. Но f просто оставил значение, которое printf было создано в этом слоте в стеке.

например, в этом коде:

#include <stdio.h>

int main(){
    printf("Hello, world!1234\n");
    printf("%d\n", f());    
}

int f(){

}

Что компилируется с gcc, а выход (в моей системе):

Привет, мир!

18

для получения подробной информации о printf() возвращаемом значении mail me.

Ответ 5

Возвращаемое по умолчанию значение из функция - int. Другими словами, если явно не указано возвращаемое по умолчанию значение компилятором быть целочисленным значением из функции.

Таким образом, утверждение omiting of return допустимо, но значение undefined будет возвращено, если вы попытаетесь его использовать.

Ответ 6

Вероятно, уровень предупреждения вашего компилятора очень низкий. Таким образом, это разрешено, даже если результат undefined.

Ответ 7

Я компилирую с -Werror=return-type, чтобы предотвратить это. GCC выдаст ошибку, если вы не вернетесь из функции (если только она не будет возвращена).