Про C/C++ иногда говорят, что это языки, в которых есть специальный синтаксис для написания невалидных программ.
В C/C++ в функции, возвращающей что-то, отличное от void
, необязательно должен быть return что-то
.
int add(int x, int y) {
x + y;
}
Это синтаксически корректная функция, которая приведет к неопределенному поведению. Может быть мусор, может быть провал в код следующей далее по коду функции, а может быть и «все нормально».
А с современными версиями компиляторов, например, Clang 18, можно получить совершенно безумный по своей красоте результат сравнимый с работой популярных ИИ-ассистентов
__attribute__((noinline))
bool is_even(int x) {
switch (x) {
case 0: return true;
case 1: return false;
case 2: return true;
case 3: return false;
// Undefined behaviour, do your job!
}
}
int main() {
std::cout << is_even(19) << "\n";
std::cout << is_even(200) << "\n";
}
# Сгенерированный код совершенно точно делает то, что мы и подразумевали!
is_even(int): # @is_even(int)
test dil, 1
sete al
ret
Особенную боль недоразумение с забытым return
может доставить тем, кто пришел в C++ после какого-нибудь ориентированного на выражения языка, в котором похожий код абсолютно нормален:
fn add(x: i32, y: i32) -> i32 {
x + y
}
Обоснования, почему не обязательно писать в конце функции return
, следующие:
- В функции может быть ветвление логики. В одной из веток может вызываться код, который не предполагает возврата: бесконечный цикл, исключение,
std::exit
,std::longjmp
или что-то иное, помеченное аттрибутом[[noreturn]]
. Проверить на наличие такого кода не всегда возможно. - Функция может содержать ассемблерную вставку со специальным кодом финализации и инструкцией
ret
.
Проверить наличие формального return
, конечно, можно. Но нам разрешили не писать иногда (очень иногда!) чисто формальную строчку, а компиляторам разрешили не считать это ошибкой.
С флагом -Wreturn-type
GCC и clang во многих случаях сообщают о проблеме.
Единственным исключением, начиная с C++11, является функция main
. В ней отсутствующий return
к неопределенному поведению не приводит и трактуется как возврат 0.