Почему главная функция без оператора return возвращает значение 12? - PullRequest
15 голосов
/ 16 сентября 2010

Я написал программу, которая печатает таблицу. Я не включил синтаксис возврата в основную функцию, но все же всякий раз, когда я набираю echo $? отображается 12.

Мой исходный код:

#include <stdio.h>


int main(void)
{
    int ans,i,n;
    printf("enter the no. : ");
    scanf("%d",&n);

    for(i=1;i<=10;i++)
    {
        ans = n*i;
        printf("%d * %d = %d\n",n,i,ans);
    }
}

Я не написал return 12, но он все равно возвращает 12 при каждом запуске программы.

Спасибо.

Ответы [ 4 ]

20 голосов
/ 16 сентября 2010

Как говорит Swegi, это неопределенное поведение. Как говорят Стив Джессоп и др., Это неопределенное значение до C89 и указано в C99 (наблюдаемое поведение не соответствует C99)

Что в действительности происходит в большинстве сред, так это то, что возвращаемое значение из последнего printf остается в регистре, используемом для возвращаемых значений.

Так что будет 11 для n == 0, 12, если n одна цифра, 14 для двух цифр n, 16 для трех цифр n и т. Д.

18 голосов
/ 16 сентября 2010

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

В C89 (спасибо pmg за ссылку на черновой стандарт ), 5.1.2.2.3:

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

В C99, цитата из n1256, 5.1.2.2.3:

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

Таким образом, это не «неопределенное поведение»: оно ведет себя так, как будто функция main возвращает, но в C89 возвращаемое значение не указано стандартом. Для вашей программы-примера в вашей реализации возвращаемое значение будет, по-видимому, равным 12, предположительно по причине, которую говорит Бен Фойгт. Поскольку вы работаете в Linux, вероятно, нет ничего особенного в том, чтобы компилировать ваш код как C99 (или в любом случае, скомпилировать его, используя почти совместимый с gcc режим C99).

Для любой функции, которая возвращает значение, отличное от main, оно равно неопределенному поведению, , если вызывающая сторона не использует возвращаемое значение (n1256, 6.9.1 / 12):

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

Я не уверен, следует ли упоминать начальный вызов main как исключенный из этого общего правила. Это не должно быть: из POV стандарта этот вызов не имеет вызывающей стороны, поэтому я думаю, что значение вызова функции не «используется вызывающей стороной», даже если оно становится статусом завершения. для программы.

1 голос
/ 16 сентября 2010

Если вы вообще знакомы с языком ассемблера, вы можете вспомнить, что «возвращаемое значение» функции передается через регистр EAX.

В этом случае возвращаемое значение читается изEAX.В данном случае это значение равно 12.

Однако вы не устанавливаете это значение явно, это просто артефакт из остальной части кода (или, возможно, просто случайность).

Как уже было сказано, это определенно undefined behavior.Если вам просто любопытно, почему это так, рассмотрите это объяснение.

Но ни при каких обстоятельствах не пытайтесь преднамеренно использовать это значение как нечто осмысленное.

0 голосов
/ 16 сентября 2010

Ваша программа вызывает неопределенное поведение, не возвращая ничего, когда это должно, поэтому вызывающая программа обычно получает то, что когда-либо значение регистра eax (на x86, rax на x64) во время возврата процедуры, которая обычно мусор от последнего использования eax (функциями, возвращающими значения или просто регистрирующими переменные), в этом случае это, вероятно, количество символов, которые printf записал в буфер stdout

...