Ini mungkin jawaban yang lebih rinci daripada yang Anda inginkan, tetapi saya pikir penjelasan yang layak dibenarkan.
Dalam C dan C ++, satu file sumber didefinisikan sebagai satu unit terjemahan . Secara konvensi, file header memiliki deklarasi fungsi, ketik definisi, dan definisi kelas. Implementasi fungsi aktual berada di unit terjemahan, yaitu file .cpp.
Gagasan di balik ini adalah bahwa fungsi dan fungsi anggota kelas / struct dikompilasi dan dirakit sekali, maka fungsi lain dapat memanggil kode itu dari satu tempat tanpa membuat duplikat. Fungsi Anda dinyatakan sebagai "eksternal" secara implisit.
/* Function declaration, usually found in headers. */
/* Implicitly 'extern', i.e the symbol is visible everywhere, not just locally.*/
int add(int, int);
/* function body, or function definition. */
int add(int a, int b)
{
return a + b;
}
Jika Anda ingin fungsi menjadi lokal untuk unit terjemahan, Anda mendefinisikannya sebagai 'statis'. Apa artinya ini? Ini berarti bahwa jika Anda memasukkan file sumber dengan fungsi eksternal, Anda akan mendapatkan kesalahan redefinisi, karena kompiler menemukan implementasi yang sama lebih dari sekali. Jadi, Anda ingin semua unit terjemahan Anda melihat deklarasi fungsi tetapi bukan badan fungsi .
Jadi bagaimana semua itu dihaluskan bersama pada akhirnya? Itu adalah tugas penghubung. Linker membaca semua file objek yang dihasilkan oleh tahap assembler dan menyelesaikan simbol. Seperti yang saya katakan sebelumnya, simbol hanyalah sebuah nama. Misalnya, nama variabel atau fungsi. Ketika unit terjemahan yang memanggil fungsi atau menyatakan tipe tidak mengetahui implementasi untuk fungsi atau tipe tersebut, simbol tersebut dikatakan tidak terselesaikan. Linker menyelesaikan simbol yang tidak terselesaikan dengan menghubungkan unit terjemahan yang menyimpan simbol yang tidak ditentukan bersama dengan yang berisi implementasi. Fiuh. Ini berlaku untuk semua simbol yang terlihat secara eksternal, apakah simbol tersebut diimplementasikan dalam kode Anda, atau disediakan oleh perpustakaan tambahan. Perpustakaan sebenarnya hanya arsip dengan kode yang dapat digunakan kembali.
Ada dua pengecualian penting. Pertama, jika Anda memiliki fungsi kecil, Anda bisa membuatnya sejajar. Ini berarti bahwa kode mesin yang dihasilkan tidak menghasilkan panggilan fungsi eksternal, tetapi secara harfiah digabungkan di tempat. Karena mereka biasanya kecil, ukuran overhead tidak masalah. Anda dapat membayangkan mereka statis dalam cara mereka bekerja. Jadi aman untuk mengimplementasikan fungsi inline di header. Implementasi fungsi di dalam kelas atau definisi struct juga sering diuraikan secara otomatis oleh kompiler.
Pengecualian lainnya adalah templat. Karena kompiler perlu melihat definisi tipe templat keseluruhan saat membuat instance, tidak mungkin memisahkan implementasi dari definisi tersebut dengan fungsi mandiri atau kelas normal. Yah, mungkin ini mungkin sekarang, tetapi mendapatkan dukungan kompiler yang tersebar luas untuk kata kunci "ekspor" membutuhkan waktu yang sangat lama. Jadi tanpa dukungan untuk 'ekspor', unit terjemahan mendapatkan salinan lokal mereka sendiri dari jenis dan fungsi templated instantiated, mirip dengan bagaimana fungsi inline bekerja. Dengan dukungan untuk 'ekspor', ini tidak terjadi.
Untuk dua pengecualian, beberapa orang merasa "lebih baik" untuk meletakkan implementasi fungsi inline, fungsi templated, dan tipe templated dalam file .cpp, dan kemudian # sertakan file .cpp. Apakah ini header atau file sumber tidak terlalu penting; preprocessor tidak peduli dan hanya sebuah konvensi.
Ringkasan cepat seluruh proses mulai dari kode C ++ (beberapa file) dan hingga yang dapat dieksekusi akhir:
- The preprocessor dijalankan, yang mem-parsing semua arahan yang dimulai dengan '#'. Arahan #include menggabungkan file yang disertakan dengan inferior, misalnya. Ini juga melakukan penggantian makro dan menempelkan token.
- Compiler aktual berjalan pada file teks perantara setelah tahap preprocessor, dan memancarkan kode assembler.
- The assembler berjalan pada file perakitan dan memancarkan kode mesin, ini biasanya disebut file objek dan mengikuti format biner dari sistem operasi tersebut. Sebagai contoh, Windows menggunakan PE (format portable executable), sedangkan Linux menggunakan format Unix System V ELF, dengan ekstensi GNU. Pada tahap ini, simbol masih ditandai sebagai tidak terdefinisi.
- Akhirnya, linker dijalankan. Semua tahap sebelumnya dijalankan pada setiap unit terjemahan secara berurutan. Namun, tahap tautan bekerja pada semua file objek yang dihasilkan yang dihasilkan oleh assembler. Linker menyelesaikan simbol dan melakukan banyak keajaiban seperti membuat bagian dan segmen, yang tergantung pada platform target dan format biner. Pemrogram tidak diharuskan untuk mengetahui hal ini secara umum, tetapi pasti membantu dalam beberapa kasus.
Sekali lagi, ini jelas lebih dari yang Anda minta, tapi saya harap detail seluk beluk membantu Anda melihat gambaran yang lebih besar.