Saya bertanya karena kompiler saya tampaknya berpikir demikian, meskipun saya tidak.
echo 'int main;' | cc -x c - -Wall
echo 'int main;' | c++ -x c++ - -Wall
Clang tidak mengeluarkan peringatan atau kesalahan dengan ini, dan gcc hanya mengeluarkan peringatan lemah lembut:, 'main' is usually a function [-Wmain]
tetapi hanya jika dikompilasi sebagai C. Menentukan a -std=
tampaknya tidak penting.
Jika tidak, itu mengkompilasi dan menautkan dengan baik. Tapi saat dieksekusi, itu segera berakhir dengan SIGBUS
(untuk saya).
Membaca jawaban (sangat baik) di What should main () return dalam C dan C ++? dan melihat sekilas spesifikasi bahasa, bagi saya jelas terlihat bahwa fungsi utama diperlukan. Tapi verbiage dari gcc's -Wmain
('main' biasanya merupakan sebuah fungsi) (dan kelangkaan error di sini) sepertinya menyarankan sebaliknya.
Tapi kenapa? Apakah ada penggunaan kasus tepi atau "historis" yang aneh untuk ini? Ada yang tahu apa yang memberi?
Maksud saya, saya kira, adalah saya benar-benar berpikir ini harus menjadi kesalahan dalam lingkungan yang dihosting, eh?
gcc -std=c99 -pedantic ...
-pedantic
atau apapun-std
. Sistem sayac99
juga mengkompilasi ini tanpa peringatan atau kesalahan ...main
, yang kemungkinan tidak akan berfungsi. Jika Anda menginisialisasi main dengan nilai yang "benar", itu mungkin benar-benar mengembalikan ...main
)main=195;
Jawaban:
Karena pertanyaannya diberi tag ganda sebagai C dan C ++, alasan untuk C ++ dan C akan berbeda:
xyz
dan fungsi global yang berdiri sendirixyz(int)
. Namun, namanyamain
tidak pernah rusak.Itulah yang terjadi di sini: penaut berharap menemukan simbol
main
, dan memang demikian. Ini "menyambungkan" simbol itu seolah-olah itu adalah sebuah fungsi, karena tidak ada yang lebih baik. Porsi pustaka runtime yang melewati kontrol untukmain
meminta linkermain
, jadi linker memberinya simbolmain
, membiarkan fase link selesai. Tentu saja ini gagal saat runtime, karenamain
bukan fungsi.Berikut ilustrasi lain dari masalah yang sama:
file xc:
file yc:
menyusun:
Ini mengkompilasi, dan itu mungkin akan berjalan, tetapi ini adalah perilaku yang tidak ditentukan, karena jenis simbol yang dijanjikan kepada kompilator berbeda dari simbol sebenarnya yang diberikan ke linker.
Sejauh peringatan berjalan, saya pikir itu masuk akal: C memungkinkan Anda membangun perpustakaan yang tidak memiliki
main
fungsi, sehingga kompilator membebaskan namamain
untuk penggunaan lain jika Anda perlu mendefinisikan variabelmain
karena alasan yang tidak diketahui.sumber
main
tidak tunduk pada nama mangling (jadi sepertinya) di C ++, apakah itu fungsi atau tidak.main
sebagai apa pun selain fungsi. Jawabannya menawarkan penjelasan untuk kedua bagian tersebut.main
bukan kata reserved itu hanya identifier yang telah ditetapkan (seperticin
,endl
,npos
...), sehingga Anda bisa mendeklarasikan variabel yang disebutmain
, menginisialisasi dan kemudian mencetak nilainya.Tentu saja:
main()
fungsi (perpustakaan).EDIT
Beberapa referensi:
main
bukan kata khusus (C ++ 11):C ++ 11 - [basic.start.main] 3.6.1.3
Kata yang dipesan dalam bahasa pemrograman .
Kata yang dicadangkan mungkin tidak didefinisikan ulang oleh pemrogram, tetapi kata yang ditentukan sebelumnya sering kali dapat diganti dalam beberapa kapasitas. Ini adalah kasus
main
: ada cakupan di mana deklarasi menggunakan pengenal itu mendefinisikan ulang artinya.sumber
main()
fungsi, tetapi Anda tidak bisa menghubungkannya sebagai sebuah program. Apa yang terjadi di sini adalah bahwa program "valid" sedang ditautkan tanpamain()
, hanya amain
.cin
danendl
tidak ada di namespace default - mereka ada distd
namespace.npos
adalah anggota daristd::basic_string
.main
adalah dicadangkan sebagai nama global. Tidak ada hal lain yang Anda sebutkan, ataumain
, yang ditentukan sebelumnya.main
yang diperbolehkan. C ++ mengatakan "Implementasi tidak akan menentukan fungsi utama sebelumnya" dan C mengatakan "Implementasi menyatakan tidak ada prototipe untuk fungsi ini."Apakah
int main;
program C / C ++ valid?Tidak sepenuhnya jelas apa itu program C / C ++.
Apakah
int main;
program C valid?Iya. Penerapan berdiri bebas diizinkan untuk menerima program semacam itu.
main
tidak harus memiliki arti khusus dalam lingkungan yang berdiri sendiri.Ini tidak valid di lingkungan yang dihosting.
Apakah
int main;
program C ++ valid?Dito.
Mengapa itu crash?
Program tidak harus masuk akal di lingkungan Anda . Dalam lingkungan yang berdiri sendiri, permulaan dan penghentian program, dan arti dari
main
, ditentukan oleh implementasi.Mengapa kompilator memperingatkan saya?
Kompilator mungkin memperingatkan Anda tentang apa pun yang diinginkannya, selama ia tidak menolak program yang sesuai. Di sisi lain, hanya peringatan yang diperlukan untuk mendiagnosis program yang tidak sesuai. Karena unit terjemahan ini tidak dapat menjadi bagian dari program host yang valid, pesan diagnostik dibenarkan.
Apakah
gcc
lingkungan berdiri bebas, atau lingkungan yang dihosting?Iya.
gcc
mendokumentasikan-ffreestanding
bendera kompilasi. Tambahkan, dan peringatan itu hilang. Anda mungkin ingin menggunakannya saat membangun, mis. Kernel atau firmware.g++
tidak mendokumentasikan bendera tersebut. Memasoknya sepertinya tidak berpengaruh pada program ini. Mungkin aman untuk mengasumsikan bahwa lingkungan yang disediakan oleh g ++ dihosting. Tidak adanya diagnostik dalam kasus ini merupakan bug.sumber
Ini adalah peringatan karena secara teknis tidak dilarang. Kode startup akan menggunakan lokasi simbol "main" dan melompat ke sana dengan tiga argumen standar (argc, argv dan envp). Tidak, dan pada waktu penautan tidak dapat memeriksa apakah itu benar-benar sebuah fungsi, atau bahkan memiliki argumen tersebut. Ini juga mengapa int main (int argc, char ** argv) berfungsi - kompilator tidak tahu tentang argumen envp dan kebetulan tidak digunakan, dan ini disebut pembersihan pemanggil.
Sebagai lelucon, Anda bisa melakukan sesuatu seperti
pada mesin x86 dan, mengabaikan peringatan dan hal-hal serupa, itu tidak hanya akan dikompilasi tetapi juga benar-benar berfungsi.
Seseorang menggunakan teknik yang mirip dengan ini untuk menulis (semacam) yang dapat dijalankan yang berjalan pada beberapa arsitektur secara langsung - http://phrack.org/issues/57/17.html#article . Itu juga digunakan untuk memenangkan IOCCC - http://www.ioccc.org/1984/mullender/mullender.c .
sumber
int main __attribute__ ((section (".text")))= 0xC3C3C3C3;
Apakah ini program yang valid?
Tidak.
Ini bukan program karena tidak memiliki bagian yang dapat dieksekusi.
Apakah valid untuk dikompilasi?
Iya.
Bisakah itu digunakan dengan program yang valid?
Iya.
Tidak semua kode yang dikompilasi harus dapat dieksekusi agar valid. Contohnya adalah perpustakaan statis dan dinamis.
Anda telah membuat file objek secara efektif. Ini bukan eksekusi yang valid, namun program lain dapat menautkan ke objek
main
dalam file yang dihasilkan dengan memuatnya saat runtime.Haruskah ini kesalahan?
Secara tradisional, C ++ memungkinkan pengguna untuk melakukan hal-hal yang tampaknya tidak valid digunakan tetapi sesuai dengan sintaks bahasa.
Maksud saya yakin, ini dapat diklasifikasikan ulang sebagai kesalahan, tetapi mengapa? Apa gunanya peringatan itu tidak?
Selama ada kemungkinan teoretis dari fungsionalitas ini digunakan dalam kode aktual, sangat tidak mungkin bahwa memiliki objek non-fungsi yang dipanggil
main
akan menghasilkan kesalahan menurut bahasanya.sumber
main
. Bagaimana program yang valid, yang harus memiliki fungsi yang terlihat secara eksternal bernamamain
, menautkannya?main
fungsi.int main;
definisi tidak akan terlihat.Saya ingin menambahkan jawaban yang sudah diberikan dengan mengutip standar bahasa yang sebenarnya.
Apakah 'int main;' program C yang valid?
Jawaban singkat (pendapat saya): hanya jika implementasi Anda menggunakan "lingkungan eksekusi bebas".
Semua kutipan berikut dari C11
5. Lingkungan
5.1.2 Lingkungan eksekusi
5.1.2.1 Lingkungan berdiri bebas
5.1.2.2 Lingkungan yang dihosting
5.1.2.2.1 Memulai program
Dari sini, diamati hal-hal berikut:
Dalam lingkungan eksekusi berdiri bebas, saya berpendapat bahwa ini adalah program yang valid yang tidak memungkinkan startup terjadi, karena tidak ada fungsi yang hadir untuk itu seperti yang dipersyaratkan dalam 5.1.2. Dalam lingkungan eksekusi yang dihosting, saat kode Anda memasukkan objek bernama main , itu tidak dapat memberikan nilai kembali, jadi saya berpendapat bahwa itu bukan program yang valid dalam pengertian ini, meskipun seseorang juga dapat berdebat seperti sebelumnya jika program tersebut tidak dimaksudkan untuk dieksekusi (pada mungkin ingin memberikan data hanya misalnya), maka itu tidak memungkinkan untuk melakukan hal itu.
Apakah 'int main;' program C ++ yang valid?
Jawaban singkat (pendapat saya): hanya jika implementasi Anda menggunakan "lingkungan eksekusi bebas".
Kutipan dari C ++ 14
3.6.1 Fungsi utama
Di sini, sebagai lawan dari standar C11, lebih sedikit batasan yang diterapkan pada lingkungan eksekusi berdiri bebas, karena tidak ada fungsi startup yang disebutkan sama sekali, sedangkan untuk lingkungan eksekusi yang dihosting, kasusnya hampir sama dengan C11.
Sekali lagi, saya berpendapat bahwa untuk kasus yang dihosting, kode Anda bukan program C ++ 14 yang valid, tetapi saya yakin itu untuk kasus yang berdiri sendiri.
Karena jawaban saya hanya mempertimbangkan lingkungan eksekusi , saya pikir jawaban dasblinkenlicht ikut bermain, karena nama mangling yang terjadi di lingkungan penerjemahan terjadi sebelumnya. Di sini, saya tidak begitu yakin bahwa kutipan di atas diamati dengan sangat ketat.
sumber
Kesalahan itu milik Anda. Anda tidak menentukan fungsi bernama
main
yang mengembalikanint
dan mencoba menggunakan program Anda di lingkungan yang dihosting.Misalkan Anda memiliki unit kompilasi yang mendefinisikan variabel global bernama
main
. Ini mungkin legal dalam lingkungan berdiri bebas karena apa yang merupakan program diserahkan kepada penerapan dalam lingkungan berdiri bebas.Misalkan Anda memiliki unit kompilasi lain yang mendefinisikan fungsi global bernama
main
yang mengembalikanint
dan tidak membutuhkan argumen. Inilah yang dibutuhkan program dalam lingkungan yang dihosting.Semuanya baik-baik saja jika Anda hanya menggunakan unit kompilasi pertama di lingkungan yang berdiri sendiri dan hanya menggunakan yang kedua di lingkungan yang dihosting. Bagaimana jika Anda menggunakan keduanya dalam satu program? Di C ++, Anda telah melanggar aturan satu definisi. Itu adalah perilaku yang tidak terdefinisi. Di C, Anda telah melanggar aturan yang menyatakan bahwa semua referensi ke satu simbol harus konsisten; jika tidak, itu adalah perilaku yang tidak terdefinisi. Perilaku tidak terdefinisi adalah "keluar dari penjara, gratis!" kartu kepada pengembang implementasi. Apa pun yang dilakukan implementasi sebagai respons terhadap perilaku yang tidak ditentukan akan sesuai dengan standar. Implementasinya tidak harus memperingatkan, apalagi mendeteksi, perilaku tidak terdefinisi.
Bagaimana jika Anda menggunakan hanya satu dari unit kompilasi itu, tetapi Anda menggunakan yang salah (yang mana yang Anda lakukan)? Di C, situasinya jelas. Kegagalan untuk menentukan fungsi
main
di salah satu dari dua bentuk standar di lingkungan yang dihosting adalah perilaku yang tidak ditentukan. Misalkan Anda tidak mendefinisikanmain
sama sekali. Compiler / linker tidak perlu mengatakan apapun tentang kesalahan ini. Bahwa mereka mengeluh adalah kebaikan atas nama mereka. Bahwa program C dikompilasi dan ditautkan tanpa kesalahan adalah kesalahan Anda, bukan kompiler.Ini agak kurang jelas di C ++ karena kegagalan untuk mendefinisikan fungsi
main
di lingkungan yang dihosting adalah kesalahan daripada perilaku yang tidak ditentukan (dengan kata lain, ini harus didiagnosis). Namun, aturan satu definisi dalam C ++ berarti penaut bisa jadi agak bodoh. Tugas penaut adalah menyelesaikan referensi eksternal, dan berkat aturan satu definisi, penaut tidak harus mengetahui arti simbol tersebut. Anda menyediakan simbol bernamamain
, linker mengharapkan untuk melihat simbol bernamamain
, jadi semuanya baik-baik saja sejauh yang bersangkutan linker.sumber
Untuk C sejauh ini adalah implementasi perilaku yang ditentukan.
Seperti yang dikatakan ISO / IEC9899:
sumber
Tidak, ini bukan program yang valid.
Untuk C ++ ini baru-baru ini secara eksplisit dibuat tidak benar oleh laporan cacat 1886: Hubungan bahasa untuk main () yang mengatakan:
dan bagian dari resolusi termasuk perubahan berikut:
Kita dapat menemukan kata-kata ini dalam standar draf C ++ N4527 terbaru yang merupakan draf C ++ 1z.
Versi terbaru dari clang dan gcc sekarang menjadikan ini sebagai kesalahan ( lihat langsung ):
Sebelum laporan kerusakan ini, itu adalah perilaku tidak terdefinisi yang tidak memerlukan diagnostik. Di sisi lain, kode yang bentuknya buruk memerlukan diagnostik, kompilator dapat menjadikannya sebagai peringatan atau kesalahan.
sumber
main()
.) Saya memahami alasan untuk melarangmain()
memiliki spesifikasi tautan eksplisit, tetapi saya tidak mengerti itu mengamanatkan yangmain()
memiliki tautan C ++ . Tentu saja standar tidak langsung alamat bagaimana menangani ABI linkage / nama mangling, tetapi dalam prakteknya (katakanlah, dengan Itanium ABI) ini akan memotong-motongmain()
untuk_Z4mainv
. Apa yang saya lewatkan?