2011-12-30 15 views
116

Stavo leggendoPerché main non restituisce 0 qui?

ISO/IEC 9899: 201x Comitato Progetto - 12 Aprile 2011

in cui ho trovato sotto cessazione 5.1.2.2.3 programma

..reaching the } that terminates the main function returns a value of 0. 

significa se non si specifica alcuna dichiarazione di reso in main() e se il programma viene eseguito correttamente, alla parentesi di chiusura} di main verrà restituito 0.

Ma nel foll grazie codice che non si specifica alcuna dichiarazione di ritorno, ma non restituisce 0

#include<stdio.h> 
int sum(int a,int b) 
{ 
return (a + b); 
} 

int main() 
{ 
    int a=10; 
    int b=5; 
    int ans;  
    ans=sum(a,b); 
    printf("sum is %d",ans); 
} 

compilare

gcc test.c 
./a.out 
sum is 15 
echo $? 
9   // here it should be 0 but it shows 9 why? 
+0

Hai compilato con un compilatore C99 (o superiore)? – pmg

+69

+1 per avere la pazienza di leggere le specifiche ..... – Asher

+0

ho compilato con gcc senza opzioni/flag extra? –

risposta

140

Tale regola è stata aggiunta nella versione del 1999 dello standard C. In C90, lo stato restituito non è definito.

È possibile abilitare il passaggio da -std=c99 a gcc.

Come nota a margine, è interessante restituire 9 perché è il risultato di printf che ha appena scritto 9 caratteri.

+8

grazie. gcc -std = c99 test.c fornisce 0 –

+40

Oppure puoi semplicemente aggiungere 'return 0;' prima della chiusura '}'. È innocuo e rende il tuo programma portatile per i compilatori più vecchi. –

+0

fa di main restituirà 0 è aggiunto in c99 o la sua parte della versione precedente di c? –

15

Restituisce il valore restituito di printf che è il numero di caratteri realmente stampato.

+0

la domanda non parla di ciò che è stampato nella consolle durante l'esecuzione del programma, parla del valore di ritorno del programma: (puoi ottenerlo in linux con il comando schell: echo $? E in windows con: echo% errorlevel%) –

+1

@eharvest Anche se non so come controllare '% errorlevel%' in Windows, c'è qualche differenza tra il codice di uscita e il valore di ritorno di 'main' in linux? –

+1

@eharvest: la risposta non parla di ciò che viene stampato anche nella console. Parla del _return value_ di 'printf' che in questo caso è 9 che poi viene" promosso "come codice di uscita da' main' in qualche modo quando si usano certe versioni di gcc. –

6

Il valore restituito da una funzione è normalmente memorizzato nel registro eax della CPU, quindi l'istruzione "return 4;" di solito compilare in

mov eax, 4; 
ret; 

e tornare x (a seconda del compilatore) sarebbe qualcosa di simile:

mov eax, [ebp + 4]; 
ret; 

se non si specifica un valore di ritorno il compilatore sarà ancora sputare il " ret "ma non cambia il valore di eax. Quindi il chiamante penserà che ciò che è rimasto nel registro eax in precedenza è il valore di ritorno. Per questo esempio, di solito è il valore di ritorno printf, ma diversi compilatori genereranno un codice macchina diverso e useranno alcuni registri in modo diverso.

Questa è una spiegazione semplificata, le diverse convenzioni di chiamata e le piattaforme di destinazione svolgeranno un ruolo fondamentale, ma dovrebbero essere sufficienti informazioni per spiegare cosa sta succedendo "dietro le quinte" nel tuo esempio.

Se hai una conoscenza di base dell'assembler, vale la pena confrontare lo smontaggio di diversi compilatori. Potresti scoprire che alcuni compilatori stanno cancellando il registro eax come salvaguardia.

+11

Il compilatore _might_ fa quello. È indefinito. Potrebbe invece scegliere di spararti alla testa con una cartuccia della stampante. –

+0

@LightnessRacesinOrbit undefined non è lo stesso dell'imprevedibile, cioè da "se il compilatore esegue X, sarà conforme allo standard" non segue logicamente "il compilatore potrebbe fare X" – Owen

+0

@Owen: cita il passaggio standard che lo definisce. –