Mengapa main tidak mengembalikan 0 di sini?


116

Saya baru saja membaca

ISO / IEC 9899: 201x Panitia Draft - 12 April 2011

di mana saya temukan di bawah 5.1.2.2.3 Penghentian program

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

ini berarti jika Anda tidak menentukan pernyataan pengembalian apa pun di main(), dan jika program berjalan dengan sukses, maka pada tanda kurung kurawal} dari main akan mengembalikan 0.

Tetapi dalam kode berikut saya tidak menentukan pernyataan pengembalian apa pun, namun tidak mengembalikan 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);
}

menyusun

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

69
+1 karena memiliki kesabaran untuk membaca spesifikasi .....
Asher

16
gccdengan sendirinya (untuk versi 4.6.2) mengkompilasi bahasa yang sangat mirip tetapi tidak persis seperti C. Ia mengkompilasi GnuC89 - bahasa "secara longgar" berdasarkan C89.
pmg

2
Tanda kurung pada returnpernyataan di sum()tidak perlu. int main()seharusnya int main(void).
Keith Thompson

24
Kebingungan! = Salah ketik. Pada keyboard saya, '0' dan 'o' cukup dekat sehingga mudah menjadi yang terakhir. ;-)
The111

2
IMHO adalah spesifikasi yang cukup bodoh, karena memaksa kompilator untuk mengelola fungsi "main" dengan cara khusus dengan menambahkan "return 0" implisit. Jadi fungsi bernama "main" berperilaku sedikit berbeda. Bagaimana dengan pemeriksaan waktu kompilasi ("tidak ada nilai kembali" yang serupa)?
Giuseppe Guerrini

Jawaban:


141

Aturan itu ditambahkan pada standar C versi 1999. Di C90, status yang dikembalikan tidak ditentukan.

Anda dapat mengaktifkannya dengan meneruskan -std=c99ke gcc.

Sebagai catatan tambahan, menariknya 9 dikembalikan karena memang pengembaliannya printfbaru aja 9 karakter.


40
Atau Anda bisa menambahkan return 0;sebelum penutupan }. Tidak berbahaya dan membuat program Anda portabel untuk kompiler yang lebih tua.
Keith Thompson

2
@ Mr.32: observasi yang baik, printf () mengembalikan panjang string jadi 9 yang merupakan "return" dari main (tanpa menggunakan -std = c99).
Hicham

1
@cnicutar: Fungsi biasanya tidak mengembalikan nilai kecil pada tumpukan — karena akan melibatkan pop, dorongan, dan lompatan, bukan hanya bergerak dan kembali — jadi hampir pasti ini adalah register, eaxkhususnya pada x86.
Jon Purdy

8
Ya, x86 API biasanya mengembalikan nilai seperti integer melalui eaxregister. Lihat en.wikipedia.org/wiki/X86_calling_conventions#cdecl untuk informasi lebih lanjut.
Sylvain Defresne

2
Beberapa kali saya melihat kode seperti "int foo (void) {bar ();}", dimana "return bar ()" dimaksudkan. Kode ini berfungsi dengan baik pada kebanyakan prosesor, meskipun ada bug yang jelas.
ugoren

15

Ia mengembalikan nilai printfyang merupakan jumlah karakter yang benar-benar dicetak.


pertanyaan tidak berbicara tentang apa yang dicetak di konsol saat menjalankan program, ini berbicara tentang nilai kembalian program: (Anda bisa mendapatkannya di linux dengan perintah schell: echo $? dan di windows dengan: echo% errorlevel% )
Hicham

1
@eharvest Meskipun saya tidak tahu cara memeriksa %errorlevel%di Windows, apakah ada perbedaan antara kode keluar dan nilai pengembalian maindi linux?
Summer_More_More_Tea

1
@eharvest: Jawabannya tidak berbicara tentang apa yang dicetak di konsol juga. Ini berbicara tentang nilai kembali dari printfyang dalam hal ini adalah 9 yang kemudian akan "dipromosikan" sebagai kode keluar dari mainentah bagaimana bila menggunakan versi gcc tertentu.
H

Maaf. kesalahanku. kamu benar. saya membaca jawaban ini terlalu cepat: /
Hicham

1
Perhatikan bahwa ini tidak dijamin. Di C89 / C90, status yang dikembalikan dalam kasus ini tidak ditentukan ; bisa apa saja. Itu terjadi untuk mengembalikan 9 karena kompilator tidak berusaha mengembalikan apa pun. Kompiler lain mungkin akan berperilaku berbeda.
Keith Thompson

6

Nilai kembali dari suatu fungsi biasanya disimpan dalam register eax dari cpu, jadi pernyataan "return 4;" biasanya akan dikompilasi menjadi

mov eax, 4;
ret;

dan kembalikan x (tergantung pada kompiler Anda) akan menjadi seperti ini:

mov eax, [ebp + 4];
ret;

jika Anda tidak menentukan nilai yang dikembalikan maka kompilator akan tetap mengeluarkan "ret" tetapi tidak mengubah nilai eax. Jadi pemanggil akan berpikir bahwa apa yang tersisa di register eax sebelumnya adalah nilai kembali. Untuk contoh ini biasanya akan menjadi nilai kembali printf, tetapi kompiler yang berbeda akan menghasilkan kode mesin yang berbeda dan menggunakan beberapa register secara berbeda.

Ini adalah penjelasan yang disederhanakan, konvensi panggilan yang berbeda dan platform target akan memainkan peran penting, tetapi informasi tersebut harus cukup untuk menjelaskan apa yang terjadi 'di balik layar' dalam contoh Anda.

Jika Anda memiliki pemahaman dasar tentang assembler, ada baiknya membandingkan pembongkaran berbagai kompiler. Anda mungkin menemukan bahwa beberapa kompiler membersihkan register eax sebagai pengaman.


11
Kompilator mungkin melakukan itu. Itu tidak ditentukan. Ia mungkin malah memilih untuk menembak Anda di kepala dengan kartrid printer.
Balapan Ringan di Orbit

@LightnessRacesinOrbit tidak terdefinisi tidak sama dengan tidak dapat diprediksi, yaitu dari "jika kompilator melakukan X, itu akan menjadi standar yang sesuai" itu tidak secara logis mengikuti "kompilator mungkin melakukan X"
Owen

@ Owen: Kutip bagian standar yang mendefinisikan ini.
Balapan Ringan di Orbit

2
@LightnessRacesinOrbit Maaf, saya kurang mengikuti. Saya rasa apa yang benar-benar ingin saya katakan adalah bahwa menurut saya wawasan yang tersembunyi seperti noggin182 yang disediakan dalam jawaban ini sangat berguna untuk debugging. Ketika program Anda memberikan hasil yang tidak diharapkan, sering kali Anda tidak tahu dari mana asalnya atau bahkan di mana kode harus dicari, dan memiliki pemahaman tentang detail implementasi dapat mengarahkan Anda ke arah yang benar.
Owen

@Owen saya tidak pernah mengklaim sebaliknya
Lightness Races di Orbit
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.