Почему этот код по-прежнему работает?
Какой-то старый код, с которым я только что столкнулся:
MLIST * new_mlist_link()
{
MLIST *new_link = (MLIST * ) malloc(sizeof(MLIST));
new_link->next = NULL;
new_link->mapi = NULL;
new_link->result = 0;
}
Это вызывалось для создания связанного списка, однако я заметил, что нет инструкции:
return new_link;
Даже без возвращаемого утверждения список по-прежнему создается правильно. Почему это произошло?
Изменить: Платформа: Mandriva 2009 64bit Linux 2.6.24.7-сервер GCC 4.2.3-6mnb1
Edit: Funny... этот код также успешно работал примерно на 5 различных установках Linux, всех разных версиях/ароматах, а также на Mac.
Ответы
Ответ 1
В 32-разрядной Windows большую часть времени возвращаемое значение из функции остается в регистре EAX. Подобные установки используются в других операционных системах, хотя, конечно, они специфичны для компилятора. Эта конкретная функция предположительно сохранила новую переменную new_link в том же месте, поэтому, когда вы вернулись без возврата, переменная в этом местоположении была обработана вызывающим абонентом как возвращаемое значение.
Это не переносится и очень опасно для этого, но также является одной из мелочей, которые делают программирование на C таким большим удовольствием.
Ответ 2
Возможно, он просто использовал регистр EAX, который обычно сохраняет возвращаемое значение последней вызванной функции. Это совсем не хорошая практика! Поведение для такого рода вещей - undefined.. Но здорово видеть работу; -)
Ответ 3
Это в основном удача; по-видимому, компилятор, похоже, придерживается new_link в том же месте, в котором он будет придерживаться возвращаемого значения.
Ответ 4
Чтобы избежать этой проблемы, используйте:
-Wreturn-type
:
Предупреждать, когда функция определена с типом возвращаемого значения, которое по умолчанию соответствует int. Также предупреждайте о любом возвращаемом выражении без возвращаемого значения в функции, тип возвращаемого которой не является недействительным (падение с конца тела функции считается возвратом без значения), а также оператор return с выражением в функции, return-type недействителен.
-Werror=return-type
, чтобы превратить это в ошибку:
Вывести указанное предупреждение в сообщение об ошибке. Спецификатор для предупреждения добавляется, например -Werror = переключает предупреждения, управляемые -Wswitch, на ошибки. Этот переключатель принимает отрицательную форму, которая должна использоваться для отрицания -Werror для определенных предупреждений, например -Wno-error = switch делает -Wswitch предупреждениями не являются ошибки, даже когда -Werror действует. Вы можете использовать опцию -fdiagnostics-show-option, чтобы каждое контролируемое предупреждение было изменено с помощью опции, которая ее контролирует, чтобы определить, что использовать с этой опцией.
(from Параметры предупреждения GCC)
Ответ 5
Это работает по совпадению. Вы не должны полагаться на это.
Ответ 6
Скорее всего, это будет очень сложно найти ошибку. Я не знаю, где я его читаю, но я помню, что если вы забудете включить оператор return, большинство компиляторов по умолчанию вернут void.
Вот короткий пример:
#include <iostream>
using namespace std;
int* getVal();
int main()
{
int *v = getVal();
cout << "Value is: " << *v << endl;
return 0;
}
int* getVal()
{
// return nothing here
}
Для меня это тоже работает. Однако, когда я запускаю его, я получаю ошибку сегмента. Так что это действительно undefined. Просто потому, что он компилируется, не означает, что он сработает.
Ответ 7
Это работает, потому что в 1940 году, когда был создан язык C, ключевого слова return
не было. Если вы посмотрите в разделе "функции" стандарта C43 MINSI, он должен это сказать по этому вопросу (между прочим):
16.4.3b For backwards compatibility the EAX register MUST be used to return
the address of the first chunk of memory allocated by malloc.
</humour>
Ответ 8
Вероятно, совпадение:
Пространство для возвращаемого значения функции назначается заранее. Поскольку это значение не инициализировано, оно могло бы указывать на то же пространство в куче, что и память, выделенная для структуры.