2010-09-16 8 views
15

Я написал программу, которая печатает таблицу. Я не включил синтаксис возврата в основную функцию, но все же, когда я набираю echo $? он показывает 12.Почему основная функция без возвращаемого выражения возвращает значение 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); 
    } 
} 

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

Спасибо.

+1

+1 хороший вопрос. :) – Pavitar

+0

http://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c –

ответ

19

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

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

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

+5

Это на самом деле неуказанное поведение. –

+0

+1: хороший нейтрально-нейтральный ответ (у кого есть реальная машина на основе стека?;)) – snemarch

+1

(-1, ну давайте посмотрим), потому что это не неопределенное поведение, но на C89 оно специфично для реализации, а в C99 поведение, которое наблюдается, явно не соответствует. (+1 для приятного объяснения, что происходит, ну, что вам повезло) –

1

неопределенное поведение

+2

Из 5.1.2.2.3 Окончание программы: «Если тип возврата основной функции тип, совместимый с int ... достигая}, который завершает основную функцию, возвращает значение 0 ". Но эта спецификация кажется новой в 'c99' (не в' ansi'). –

+1

@jleedev: текст «C89» аналогичен: «Если функция, которая завершает основную функцию, достигнута, статус завершения, возвращаемый в среду хоста, не указан». (src: http://www.vmunix.com/~gabor/c/draft.html) – pmg

+1

@pmg: Я не считаю, что это очень похоже. Один из них утверждает конкретное поведение конкретной реализации, другие силы - это возврат '0'. –

1

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

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

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

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

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

+6

Это ограничено архитектурой x86. Они могут быть наиболее распространенными, но утверждать, что это универсальный факт определенно неверен. –

+5

Нет, это не неопределенное поведение. Для C89 это специфичная реализация, а для C99 '0' должно быть возвращено. –

+0

Хорошо, на ARM там то же самое можно сказать о r0 – doron

0

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

18

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

В C89 (благодаря PMG для ссылки на draft standard), 5.1.2.2.3:

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

В C99, цитируя n1256, 5.1.2.2.3:

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

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

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

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

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

+2

Фактический стандарт ISO ISO 1990 (и, предположительно, стандарт ANSI 1989 года) гласит, что «статус завершения, возвращенный в среду хоста, не определен». По-видимому, слово было изменено с «неуказанного» на «неопределенное» между проектом и публикацией стандарта. Кстати, [эта ссылка, кажется, мертва] (http://www.vmunix.com/~gabor/c/draft.html). –