Почему это кодировало все еще работу?

Некоторый старый код, с которым я просто столкнулся:

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 Linux на 64 бита 2009 года, с 2.6.24.7 серверами GCC 4.2.3-6mnb1

Править: Забавное... этот код также работал успешно приблизительно на 5 различных установках Linux, всех различных версиях/разновидностях, а также Mac.

29
задан user318747 31 May 2010 в 02:16
поделиться

8 ответов

В 32-битной Windows большую часть времени возвращаемое значение функции остается в регистре EAX. Подобные настройки используются в других ОС, хотя, конечно, это зависит от компилятора. Эта конкретная функция предположительно сохранила переменную new_link в том же месте, поэтому, когда вы вернулись без возврата, переменная в этом месте обрабатывалась вызывающей стороной как возвращаемое значение.

Это непереносимо и очень опасно на самом деле, но это также одна из тех мелочей, которые делают программирование на C таким увлекательным.

35
ответ дан 28 November 2019 в 01:32
поделиться

Возможно, он просто использовал регистр EAX, который обычно хранит возвращаемое значение последней вызванной функции. Это совсем не лучшая практика! Поведение для такого рода вещей не определено .. Но приятно видеть работу; -)

7
ответ дан 28 November 2019 в 01:32
поделиться

Это работает по совпадению. Не стоит на это полагаться.

1
ответ дан 28 November 2019 в 01:32
поделиться

Скорее всего, это приведет к очень трудно обнаруживаемой ошибке. Я не знаю, где я это читал, но я помню, что если вы забыли вставить оператор возврата, большинство компиляторов по умолчанию возвращают 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
}

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

1
ответ дан 28 November 2019 в 01:32
поделиться

Возможно, совпадение:

Место для возвращаемого значения функции выделено заранее. Поскольку это значение неинициализировано, оно могло указывать на то же место на куче, что и память, выделенная для struct.

-1
ответ дан 28 November 2019 в 01:32
поделиться

По сути, это удача; по-видимому, компилятор вставляет new_link в то же место, где он вставляет возвращаемое значение.

5
ответ дан 28 November 2019 в 01:32
поделиться

Чтобы избежать этой проблемы , используйте:

-Wreturn-type :

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

-Werror = return-type , чтобы превратить вышеуказанное в ошибку:

Превратить указанное предупреждение в ошибку. Добавляется спецификатор предупреждения, например -Werror = switch превращает предупреждения, управляемые -Wswitch, в ошибки. Этот переключатель принимает отрицательную форму, чтобы использовать его для отмены -Werror для определенных предупреждений, например -Wno-error = switch делает предупреждения -Wswitch не ошибками, даже если действует -Werror. Вы можете использовать опцию -fdiagnostics-show-option, чтобы каждое управляемое предупреждение изменялось опцией, которая его контролирует, чтобы определить, что использовать с этой опцией.

(из Параметры предупреждений GCC )

5
ответ дан 28 November 2019 в 01:32
поделиться

Это работает, потому что в 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.

0
ответ дан 28 November 2019 в 01:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: