Pertimbangkan program berikut:
#include <iostream>
int main = ( std::cout << "C++ is excellent!\n", 195 );
Menggunakan g ++ 4.8.1 (mingw64) pada OS Windows 7, program dikompilasi dan berjalan dengan baik, mencetak:
C ++ luar biasa!
ke konsol. main
tampaknya menjadi variabel global daripada fungsi; bagaimana program ini dapat dijalankan tanpa fungsi main()
? Apakah kode ini sesuai dengan standar C ++? Apakah perilaku program didefinisikan dengan baik? Saya juga telah menggunakan -pedantic-errors
opsi tetapi program masih mengkompilasi dan berjalan.
c++
main
language-lawyer
Penghancur
sumber
sumber
195
opcode untukRET
instruksi, dan dalam konvensi pemanggilan C, pemanggil membersihkan stack.main()
fungsi? Pada kenyataannya, mereka sama sekali tidak terkait.)int main = ( std::cout << "C++ is excellent!\n", exit(0),1 );
(dan termasuk<cstdlib>
), meskipun program tersebut secara hukum tidak berbentuk.Jawaban:
Sebelum masuk ke inti pertanyaan tentang apa yang sedang terjadi, penting untuk menunjukkan bahwa program memiliki format yang salah sesuai laporan cacat 1886: Hubungan bahasa untuk main () :
Versi terbaru dari clang dan gcc membuat ini menjadi kesalahan dan program tidak dapat dikompilasi ( lihat contoh langsung gcc ):
Jadi mengapa tidak ada diagnosis di versi gcc dan clang? Laporan kerusakan ini bahkan tidak memiliki penyelesaian yang diusulkan hingga akhir 2014 dan oleh karena itu kasus ini baru-baru ini secara eksplisit bentuknya buruk, yang memerlukan diagnosis.
Sebelum ini, sepertinya ini akan menjadi perilaku tidak terdefinisi karena kita melanggar persyaratan wajib dari draf standar C ++ dari bagian
3.6.1
[basic.start.main] :Perilaku tidak terdefinisi tidak dapat diprediksi dan tidak memerlukan diagnosis. Ketidakkonsistenan yang kita lihat dengan mereproduksi perilaku adalah perilaku khas yang tidak terdefinisi.
Jadi, apa sebenarnya yang dilakukan kode tersebut dan mengapa dalam beberapa kasus kode itu membuahkan hasil? Mari kita lihat apa yang kita punya:
Kami memiliki
main
yang merupakan int dinyatakan dalam namespace global dan sedang diinisialisasi, variabel memiliki durasi penyimpanan statis. Ini adalah implementasi yang ditentukan apakah inisialisasi akan dilakukan sebelum upaya untuk memanggilmain
dilakukan tetapi tampaknya gcc melakukan ini sebelum memanggilmain
.Kode menggunakan operator koma , operan kiri adalah ekspresi nilai yang dibuang dan digunakan di sini hanya untuk efek samping pemanggilan
std::cout
. Hasil dari operator koma adalah operan kanan yang dalam hal ini adalah prvalue195
yang diberikan ke variabelmain
.Kita dapat melihat sergej menunjukkan perakitan yang dihasilkan menunjukkan yang
cout
dipanggil selama inisialisasi statis. Meskipun poin yang lebih menarik untuk diskusi melihat sesi godbolt langsung adalah ini:dan selanjutnya:
Skenario yang mungkin terjadi adalah bahwa program melompat ke simbol yang
main
mengharapkan kode valid ada di sana dan dalam beberapa kasus akan seg-fault . Jadi jika itu kasusnya, kami berharap menyimpan kode mesin yang valid dalam variabelmain
dapat menghasilkan program yang bisa diterapkan , dengan asumsi kami berada di segmen yang memungkinkan eksekusi kode. Kita bisa melihat entri IOCCC 1984 melakukan hal itu .Tampaknya kita bisa mendapatkan gcc untuk melakukan ini di C menggunakan ( lihat langsung ):
Itu seg-kesalahan jika variabel
main
tidak const mungkin karena tidak terletak di lokasi yang dapat dieksekusi, Hat Tip untuk komentar ini di sini yang memberi saya ide ini.Juga lihat jawaban FUZxxl di sini untuk versi khusus C dari pertanyaan ini.
sumber
main
bukan pengenal yang dipesan (3.6.1 / 3). Dalam hal ini, menurut saya penanganan VS2013 untuk kasus ini (lihat jawaban Francis Cugler) lebih tepat dalam penanganannya daripada gcc & clang.Dari 3.6.1 / 1:
Dari sini sepertinya g ++ kebetulan mengizinkan program (mungkin sebagai klausa "berdiri bebas") tanpa fungsi utama.
Kemudian dari 3.6.1 / 3:
Jadi di sini kita belajar bahwa tidak masalah untuk memiliki variabel integer bernama
main
.Terakhir, jika Anda bertanya-tanya mengapa output dicetak, inisialisasi
int main
menggunakan operator koma untuk mengeksekusicout
pada init statis dan kemudian memberikan nilai integral aktual untuk melakukan inisialisasi.sumber
main
menjadi yang lain:(.text+0x20): undefined reference to
main '``gcc 4.8.1 menghasilkan rakitan x86 berikut:
Perhatikan bahwa
cout
dipanggil selama inisialisasi, bukan dalammain
fungsi!.zero 4
mendeklarasikan 4 (0-diinisialisasi) byte mulai dari lokasimain
, di manamain
nama variabel [!] .The
main
simbol ditafsirkan sebagai awal program. Perilakunya tergantung pada platform.sumber
195
adalah opcode untukret
beberapa arsitektur. Jadi mengatakan nol instruksi mungkin tidak akurat.Itu adalah program yang cacat. Itu macet di lingkungan pengujian saya, cygwin64 / g ++ 4.9.3.
Dari standar:
sumber
Alasan saya percaya ini berfungsi adalah bahwa kompilator tidak tahu itu sedang menyusun
main()
fungsi sehingga mengkompilasi integer global dengan efek samping tugas.The format objek yang ini terjemahan unit dikompilasi menjadi tidak mampu membedakan antara simbol fungsi dan simbol variabel .
Jadi linker dengan senang hati menautkan ke simbol utama (variabel) dan memperlakukannya seperti pemanggilan fungsi. Tetapi tidak sampai sistem runtime telah menjalankan kode inisialisasi variabel global.
Ketika saya menjalankan sampel itu dicetak tetapi kemudian itu menyebabkan kesalahan-seg . Saya berasumsi saat itulah sistem runtime mencoba mengeksekusi variabel int seolah-olah itu adalah sebuah fungsi .
sumber
Saya sudah mencoba ini pada OS Win7 64bit menggunakan VS2013 dan dikompilasi dengan benar tetapi ketika saya mencoba membangun aplikasi saya mendapatkan pesan ini dari jendela keluaran.
sumber
main()
karena merupakan variabel jenisint
Anda melakukan pekerjaan rumit di sini. Sebagai main (entah bagaimana) bisa dideklarasikan menjadi integer. Anda menggunakan operator daftar untuk mencetak pesan & kemudian menetapkan 195 padanya. Seperti yang dikatakan oleh seseorang di bawah ini, bahwa itu tidak nyaman dengan C ++, itu benar. Tetapi karena kompiler tidak menemukan nama yang ditentukan pengguna, main, itu tidak mengeluh. Ingat main bukan fungsi yang ditentukan sistem, fungsi yang ditentukan penggunanya & hal dari mana program mulai dijalankan adalah Modul Utama, bukan main (), secara khusus. Sekali lagi main () dipanggil oleh fungsi startup yang dieksekusi oleh loader secara sengaja. Kemudian semua variabel Anda diinisialisasi, & saat menginisialisasi, output seperti itu. Itu dia. Program tanpa main () oke, tapi tidak standar.
sumber