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 () :
[...] Program yang mendeklarasikan variabel utama pada lingkup global atau yang mendeklarasikan nama main dengan keterkaitan bahasa C (dalam namespace apa pun) tidak berbentuk. [...]
Versi terbaru dari clang dan gcc membuat ini menjadi kesalahan dan program tidak dapat dikompilasi ( lihat contoh langsung gcc ):
error: cannot declare '::main' to be a global variable
int main = ( std::cout << "C++ is excellent!\n", 195 );
^
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] :
Suatu program harus berisi fungsi global yang disebut main, yang merupakan permulaan program yang ditentukan. [...]
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:
declarator
| initializer----------------------------------
| | |
v v v
int main = ( std::cout << "C++ is excellent!\n", 195 );
^ ^ ^
| | |
| | comma operator
| primary expression
global variable of type int
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 memanggil main
dilakukan tetapi tampaknya gcc melakukan ini sebelum memanggil main
.
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 prvalue 195
yang diberikan ke variabel main
.
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:
main:
.zero 4
dan selanjutnya:
movl $195, main(%rip)
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 variabel main
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 ):
const int main = 195 ;
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.