Saya tahu ada dua tanda tangan berbeda untuk menulis metode utama -
int main()
{
//Code
}
atau untuk menangani argumen baris perintah, kami menuliskannya sebagai-
int main(int argc, char * argv[])
{
//code
}
Dalam C++
Aku tahu kita bisa membebani metode, tetapi dalam C
bagaimana compiler menangani dua tanda tangan yang berbeda dari main
fungsi?
main
metode dalam satu program diC
(atau, sebenarnya, dalam hampir semua bahasa dengan konstruksi seperti itu).main
- saya merekomendasikan buku klasik John R. Levines "Linkers & Loaders".int main(void)
, bukanint main()
(meskipun saya belum pernah melihat kompiler yang menolakint main()
formulir).()
Formulirnya sudah usang, dan bahkan tidak jelas apakah diizinkanmain
(kecuali jika penerapannya secara khusus mendokumentasikannya sebagai formulir yang diizinkan). Standar C (lihat 5.1.2.2.1 Memulai program) tidak menyebutkan()
formulir, yang tidak cukup setara dengan()
formulir. Detailnya terlalu panjang untuk komentar ini.Jawaban:
Beberapa fitur bahasa C dimulai sebagai peretasan yang kebetulan berhasil.
Beberapa tanda tangan untuk main, serta daftar argumen panjang-variabel, adalah salah satu fiturnya.
Pemrogram memperhatikan bahwa mereka dapat meneruskan argumen tambahan ke suatu fungsi, dan tidak ada hal buruk yang terjadi dengan kompiler yang diberikan.
Ini adalah kasus jika konvensi pemanggilan seperti itu:
Satu set konvensi pemanggil yang mematuhi aturan ini adalah pengalihan parameter berbasis tumpukan di mana pemanggil memunculkan argumen, dan mereka didorong dari kanan ke kiri:
Dalam kompiler di mana jenis konvensi pemanggilan ini terjadi, tidak ada kebutuhan khusus yang perlu dilakukan untuk mendukung dua jenis
main
, atau bahkan jenis tambahan.main
bisa menjadi fungsi tanpa argumen, dalam hal ini ia mengabaikan item yang didorong ke tumpukan. Jika ini adalah fungsi dari dua argumen, maka ia menemukanargc
danargv
sebagai dua item tumpukan paling atas. Jika itu adalah varian tiga argumen khusus platform dengan penunjuk lingkungan (ekstensi umum), itu juga akan berfungsi: ia akan menemukan argumen ketiga itu sebagai elemen ketiga dari atas tumpukan.Jadi panggilan tetap berfungsi untuk semua kasus, memungkinkan satu modul start-up tetap untuk ditautkan ke program. Modul itu bisa ditulis dalam C, dengan fungsi yang menyerupai ini:
Dengan kata lain, modul start ini hanya memanggil main tiga argumen, selalu. Jika main tidak membutuhkan argumen, atau hanya
int, char **
, itu berfungsi dengan baik, serta jika tidak membutuhkan argumen, karena konvensi pemanggilan.Jika Anda melakukan hal semacam ini dalam program Anda, itu akan menjadi perilaku nonportable dan dianggap tidak terdefinisi oleh ISO C: mendeklarasikan dan memanggil fungsi dengan satu cara, dan mendefinisikannya dengan cara lain. Tetapi trik startup kompiler tidak harus portabel; itu tidak dipandu oleh aturan untuk program portabel.
Tetapi anggaplah bahwa konvensi pemanggilan sedemikian rupa sehingga tidak dapat bekerja dengan cara ini. Dalam hal ini, kompilator harus memperlakukannya
main
secara khusus. Ketika ia mengetahui bahwa ia sedang mengompilasimain
fungsinya, ia dapat menghasilkan kode yang kompatibel dengan, katakanlah, panggilan tiga argumen.Artinya, Anda menulis ini:
Tetapi ketika kompilator melihatnya, pada dasarnya ia melakukan transformasi kode sehingga fungsi yang dikompilasinya terlihat lebih seperti ini:
kecuali bahwa nama
__argc_ignore
itu tidak ada secara harfiah. Tidak ada nama seperti itu yang dimasukkan ke dalam cakupan Anda, dan tidak akan ada peringatan tentang argumen yang tidak digunakan. Transformasi kode menyebabkan kompilator memancarkan kode dengan hubungan yang benar yang mengetahui bahwa ia harus membersihkan tiga argumen.Strategi implementasi lainnya adalah untuk compiler atau mungkin linker untuk membuat custom
__start
fungsi (atau apapun namanya), atau setidaknya pilih satu dari beberapa alternatif yang telah dikompilasi sebelumnya. Informasi dapat disimpan dalam file objek tentang bentuk yang didukungmain
yang digunakan. Linker dapat melihat info ini, dan memilih versi yang benar dari modul start-up yang berisi panggilanmain
yang kompatibel dengan definisi program. Implementasi C biasanya hanya memiliki sejumlah kecil bentuk yang didukungmain
sehingga pendekatan ini layak.Kompiler untuk bahasa C99 selalu harus memperlakukan
main
secara khusus, sampai batas tertentu, untuk mendukung peretasan yang jika fungsi berhenti tanpareturn
pernyataan, perilakunya seolah-olahreturn 0
dijalankan. Ini, sekali lagi, dapat ditangani dengan transformasi kode. Kompilator memperhatikan bahwa fungsi yang dipanggilmain
sedang dikompilasi. Kemudian ia memeriksa apakah ujung tubuh berpotensi dijangkau. Jika demikian, itu menyisipkanreturn 0;
sumber
Tidak ada overloading
main
bahkan di C ++. Fungsi utama adalah titik masuk untuk sebuah program dan seharusnya hanya ada satu definisi.Untuk Standar C
Untuk C ++ standar:
Standar C ++ secara eksplisit mengatakan "Ini [fungsi utama] harus memiliki tipe kembalian dari tipe int, tetapi jika tidak, tipenya adalah implementasi yang ditentukan", dan membutuhkan dua tanda tangan yang sama seperti standar C.
Dalam lingkungan yang dihosting ( lingkungan AC yang juga mendukung pustaka C) - Sistem Operasi memanggil
main
.Dalam lingkungan non-host (Satu ditujukan untuk aplikasi yang disematkan) Anda selalu dapat mengubah titik masuk (atau keluar) dari program Anda menggunakan arahan pra-prosesor seperti
Dimana prioritas adalah bilangan integral opsional.
Pragma startup menjalankan fungsi sebelum main (berdasarkan prioritas) dan keluar pragma menjalankan fungsi setelah fungsi utama. Jika ada lebih dari satu arahan startup, maka prioritas memutuskan mana yang akan dieksekusi terlebih dahulu.
sumber
Tidak perlu kelebihan beban. Ya, ada 2 versi, tetapi hanya satu yang dapat digunakan pada saat itu.
sumber
Ini adalah salah satu asimetri yang aneh dan aturan khusus bahasa C dan C ++.
Menurut pendapat saya, ini hanya ada karena alasan sejarah dan tidak ada logika serius di baliknya. Perhatikan bahwa
main
itu juga khusus untuk alasan lain (misalnyamain
di C ++ tidak dapat rekursif dan Anda tidak dapat mengambil alamatnya dan di C99 / C ++ Anda diizinkan untuk menghilangkanreturn
pernyataan akhir ).Perhatikan juga bahwa bahkan di C ++ ini bukan overload ... baik program memiliki bentuk pertama atau bentuk kedua; tidak bisa keduanya.
sumber
return
pernyataan di C (sejak C99).main()
dan mencatat alamatnya; C ++ menerapkan batasan yang tidak dimiliki C.argc
saat berulang (5.1.2.2.1 tidak menentukan batasan padaargc
danargv
hanya berlaku untuk panggilan awal kemain
).Apa yang tidak biasa
main
adalah bahwa itu dapat didefinisikan dengan lebih dari satu cara, itu hanya dapat didefinisikan dengan salah satu dari dua cara yang berbeda.main
adalah fungsi yang ditentukan pengguna; implementasinya tidak mendeklarasikan prototipe untuk itu.Hal yang sama berlaku untuk
foo
ataubar
, tetapi Anda dapat mendefinisikan fungsi dengan nama-nama itu sesuka Anda.Perbedaannya adalah yang
main
dipanggil oleh implementasi (lingkungan runtime), bukan hanya oleh kode Anda sendiri. Implementasinya tidak terbatas pada semantik pemanggilan fungsi C biasa, sehingga dapat (dan harus) menangani beberapa variasi - tetapi tidak diharuskan untuk menangani banyak kemungkinan yang tak terbatas. Theint main(int argc, char *argv[])
Bentuk memungkinkan untuk argumen baris perintah, danint main(void)
di C atauint main()
C ++ hanya kenyamanan bagi program sederhana yang tidak perlu proses argumen baris perintah.Adapun bagaimana kompilator menangani ini, itu tergantung pada implementasinya. Sebagian besar sistem mungkin memiliki konvensi pemanggil yang membuat dua bentuk kompatibel secara efektif, dan argumen apa pun yang diteruskan ke yang
main
ditentukan tanpa parameter akan diabaikan secara diam-diam. Jika tidak, tidak akan sulit bagi compiler atau linker untuk menanganimain
secara khusus. Jika Anda penasaran bagaimana cara kerjanya di sistem Anda, Anda mungkin melihat beberapa daftar perakitan.Dan seperti banyak hal di C dan C ++, detailnya sebagian besar merupakan hasil dari sejarah dan keputusan sewenang-wenang yang dibuat oleh perancang bahasa dan pendahulunya.
Perhatikan bahwa C dan C ++ sama-sama mengizinkan definisi yang ditentukan implementasi lainnya untuk
main
- tetapi jarang ada alasan bagus untuk menggunakannya. Dan untuk implementasi yang berdiri sendiri (seperti sistem tertanam tanpa OS), titik masuk program ditentukan oleh implementasi, dan bahkan tidak perlu dipanggilmain
.sumber
Ini
main
hanyalah nama untuk alamat awal yang ditentukan oleh linker di manamain
nama default-nya. Semua nama fungsi dalam program memulai alamat tempat fungsi dimulai.Argumen fungsi didorong / muncul di / dari tumpukan jadi jika tidak ada argumen yang ditentukan untuk fungsi, tidak ada argumen yang didorong / muncul di / di luar tumpukan. Begitulah cara main dapat bekerja dengan atau tanpa argumen.
sumber
di mana variabel argc menyimpan jumlah data yang diteruskan dan argv adalah larik pointer ke char yang menunjuk ke nilai yang diteruskan dari konsol. Kalau tidak, itu selalu bagus untuk digunakan
Namun bagaimanapun juga bisa ada satu dan hanya satu main () dalam sebuah program, karena itu adalah satu-satunya titik di mana dari sebuah program memulai eksekusinya dan karenanya tidak bisa lebih dari satu. (semoga itu layak)
sumber
Pertanyaan serupa telah ditanyakan sebelumnya: Mengapa sebuah fungsi tanpa parameter (dibandingkan dengan definisi fungsi sebenarnya) dapat dikompilasi?
Salah satu jawaban peringkat teratas adalah:
Jadi, saya kira begitulah cara
main
dideklarasikan (jika Anda dapat menerapkan istilah "dideklarasikan" kemain
). Sebenarnya Anda bisa menulis sesuatu seperti ini:dan itu akan tetap dikompilasi dan dijalankan.
sumber
main
, karena ada masalah yang belum disebutkan: bahkan lebih banyak argumen untukmain
! "Unix (tapi bukan Posix.1) dan Microsoft Windows" menambahkanchar **envp
(saya ingat DOS juga mengizinkannya, bukan?), Dan Mac OS X dan Darwin menambahkan lagi char * pointer "informasi yang disediakan OS sewenang-wenang". wikipediaAnda tidak perlu menimpa ini. Karena hanya satu yang akan digunakan dalam satu waktu. Ya ada 2 versi berbeda dari fungsi utama
sumber