Saya belajar dari rekan saya bahwa seseorang dapat menulis dan menjalankan program C tanpa menulis main()
fungsi. Itu bisa dilakukan seperti ini:
my_main.c
/* Compile this with gcc -nostartfiles */
#include <stdlib.h>
void _start() {
int ret = my_main();
exit(ret);
}
int my_main() {
puts("This is a program without a main() function!");
return 0;
}
Kompilasikan dengan perintah ini:
gcc -o my_main my_main.c –nostartfiles
Jalankan dengan perintah ini:
./my_main
Kapan seseorang perlu melakukan hal semacam ini? Apakah ada skenario dunia nyata di mana ini akan berguna?
_start()
dan hal-hal lain di luarnyamain()
._start
, atau tentang titik masuk apa pun selainmain
(kecuali bahwa nama titik masuk adalah implementasi yang ditentukan untuk implementasi berdiri bebas (tertanam)).Jawaban:
Simbol
_start
adalah titik masuk program Anda. Artinya, alamat simbol itu adalah alamat yang dilompati saat program dimulai. Biasanya, fungsi dengan nama_start
tersebut disediakan oleh file bernamacrt0.o
yang berisi kode startup untuk lingkungan runtime C. Ini mengatur beberapa hal, mengisi array argumenargv
, menghitung berapa banyak argumen yang ada, dan kemudian memanggilmain
. Setelahmain
kembali,exit
dipanggil.Jika program tidak ingin menggunakan lingkungan runtime C, program perlu menyediakan kodenya sendiri untuk
_start
. Misalnya, implementasi referensi dari bahasa pemrograman Go melakukannya karena mereka memerlukan model penguliran non-standar yang memerlukan sihir dengan tumpukan. Ini juga berguna untuk menyediakan sendiri_start
ketika Anda ingin menulis program atau program yang sangat kecil yang melakukan hal-hal yang tidak biasa.sumber
_start
berasal dari file objekcrt0.o
juga._start
; pada kenyataannya, itu tidak menentukan apa yang terjadi sebelummain
dipanggil sama sekali, itu hanya menentukan kondisi apa yang harus dipenuhi ketikamain
dipanggil. Ini lebih merupakan konvensi untuk titik masuk_start
yang tanggal kembali ke masa lalu.Sementara
main
adalah titik masuk untuk program Anda dari perspektif pemrogram,_start
adalah titik masuk biasa dari perspektif OS (instruksi pertama yang dijalankan setelah program Anda dimulai dari OS)Dalam program C dan khususnya C ++, banyak pekerjaan telah dilakukan sebelum eksekusi memasuki main.
Terutama hal-hal seperti inisialisasi variabel global.Di sini Anda dapat menemukan penjelasan yang baik tentang segala sesuatu yang terjadi antara_start()
danmain()
dan juga setelah main telah keluar lagi (lihat komentar di bawah).Kode yang diperlukan untuk itu biasanya disediakan oleh penulis kompilator dalam file startup, tetapi dengan flag
–nostartfiles
pada dasarnya Anda memberi tahu kompiler: "Jangan repot-repot memberi saya file startup standar, beri saya kendali penuh atas apa yang terjadi langsung dari Mulailah".Ini terkadang diperlukan dan sering digunakan pada sistem tertanam. Misalnya jika Anda tidak memiliki OS dan Anda harus secara manual mengaktifkan bagian tertentu dari sistem memori Anda (misalnya cache) sebelum inisialisasi objek global Anda.
sumber
_start()
(atau sebenarnya fungsi lain yang disebut olehnya) dan di banyak Bare-Metal-Program, Anda secara eksplisit menyalin semua data global dari flash ke RAM pertama, yang juga terjadi di_start()
, tetapi pertanyaan ini bukan tentang c ++ atau kode bare-metal._start
, pustaka C tidak akan diinisialisasi kecuali Anda mengambil langkah khusus untuk melakukannya sendiri - mungkin tidak aman untuk menggunakan fungsi non-async-signal-safe dari program semacam itu. (Tidak ada jaminan resmi bahwa fungsi perpustakaan apa pun akan berfungsi, tetapi fungsi async-signal-safe tidak dapat merujuk ke data global sama sekali, jadi mereka harus keluar dari jalan menuju kerusakan.)malloc
tidak diinisialisasi.errno
(misalnyaread
danwrite
yang async-sinyal-aman dan dapat mengaturerrno
) dan yang dibayangkan bisa menjadi masalah tergantung pada kapan tepatnya per-benangerrno
lokasi dialokasikan .Berikut adalah gambaran umum yang bagus tentang apa yang terjadi selama startup program sebelumnya
main
. Secara khusus, ini menunjukkan bahwa itu__start
adalah titik masuk sebenarnya ke program Anda dari sudut pandang OS.Ini adalah alamat pertama dari mana penunjuk instruksi akan mulai menghitung dalam program Anda.
Kode di sana memanggil beberapa rutinitas pustaka runtime C hanya untuk melakukan beberapa housekeeping, kemudian memanggil Anda
main
, dan kemudian menurunkan semuanya dan memanggilexit
dengan kode keluar apa pun yangmain
dikembalikan.Sebuah gambar memiliki makna ribuan kata:
PS: jawaban ini ditransplantasikan dari pertanyaan lain yang telah ditutup SO membantu sebagai duplikat dari pertanyaan ini.
sumber
Ketika Anda menginginkan kode startup Anda sendiri untuk program Anda.
main
bukan entri pertama untuk program C,_start
adalah entri pertama di balik tirai.Contoh di Linux:
Jika Anda maksud, terapkan sendiri
_start
:Ya, di sebagian besar perangkat lunak tertanam komersial yang pernah saya gunakan, kami perlu menerapkannya sendiri
_start
terkait dengan memori khusus dan persyaratan kinerja kami.Jika yang Anda maksud, hapus
main
fungsi dan ubah ke yang lain:Tidak, saya tidak melihat keuntungan melakukan itu.
sumber