Mengapa fungsi C tidak bisa diubah namanya?

137

Saya baru-baru ini melakukan wawancara dan satu pertanyaan yang diajukan adalah apa gunanya extern "C"dalam kode C ++. Saya menjawab bahwa itu untuk menggunakan fungsi C dalam kode C ++ karena C tidak menggunakan nama-mangling. Saya ditanya mengapa C tidak menggunakan nama-mangling dan sejujurnya saya tidak bisa menjawab.

Saya memahami bahwa ketika kompilator C ++ mengompilasi fungsi, ia memberikan nama khusus untuk fungsi tersebut terutama karena kita dapat memiliki fungsi yang kelebihan beban dengan nama yang sama di C ++ yang harus diselesaikan pada waktu kompilasi. Di C, nama fungsinya akan tetap sama, atau mungkin dengan _ sebelumnya.

Pertanyaan saya adalah: apa yang salah dengan mengizinkan compiler C ++ untuk mengacaukan fungsi C juga? Saya akan berasumsi bahwa tidak masalah nama apa yang diberikan kompilator kepada mereka. Kami memanggil fungsi dengan cara yang sama di C dan C ++.

Insinyur999
sumber
75
C tidak perlu mengacaukan nama, karena tidak memiliki fungsi yang berlebihan.
EOF
9
Bagaimana Anda menghubungkan pustaka C dengan kode C ++ jika kompiler C ++ merusak nama fungsinya?
Mat
6
"Saya menjawab bahwa itu untuk menggunakan fungsi C dalam kode C ++ karena C tidak menggunakan nama-mangling." - Saya pikir itu sebaliknya. Extern "C" membuat fungsi C ++ dapat digunakan dalam kompiler C. sumber
rozina
3
@ Engineer999: Dan jika Anda mengompilasi subset C yang juga merupakan C ++ dengan kompiler C ++, nama fungsi memang akan rusak. Tetapi jika Anda ingin dapat menautkan binari yang dibuat dengan kompiler yang berbeda, Anda tidak ingin menamai mangling.
EOF
13
C melakukan nama mangle. Biasanya nama yang rusak adalah nama fungsi yang diawali dengan garis bawah. Terkadang itu adalah nama fungsi yang diikuti dengan garis bawah. extern "C"mengatakan untuk mengacaukan nama dengan cara yang sama seperti yang dilakukan oleh compiler C ".
Pete Becker

Jawaban:

189

Itu semacam jawaban di atas, tetapi saya akan mencoba memasukkan semuanya ke dalam konteks.

Pertama, C datang lebih dulu. Dengan demikian, apa yang dilakukan C adalah, semacam, "default". Itu tidak merusak nama karena memang tidak. Nama fungsi adalah nama fungsi. Global adalah global, dan seterusnya.

Kemudian C ++ muncul. C ++ ingin dapat menggunakan penaut yang sama dengan C, dan dapat menautkan dengan kode yang ditulis dalam C. Tetapi C ++ tidak dapat meninggalkan C "mangling" (atau, kekurangannya) sebagaimana adanya. Lihat contoh berikut:

int function(int a);
int function();

Dalam C ++, ini adalah fungsi yang berbeda, dengan badan yang berbeda. Jika tidak ada satupun yang rusak, keduanya akan disebut "fungsi" (atau "_fungsi"), dan penaut akan mengeluh tentang definisi ulang simbol. Solusi C ++ adalah untuk mengacaukan tipe argumen ke dalam nama fungsi. Jadi, yang satu dipanggil _function_intdan yang lainnya dipanggil_function_void (bukan skema mangling yang sebenarnya) dan tabrakan dihindari.

Sekarang kita punya masalah. Jika int function(int a)didefinisikan dalam modul C, dan kita hanya mengambil headernya (yaitu deklarasi) dalam kode C ++ dan menggunakannya, kompilator akan membuat instruksi ke linker untuk diimpor _function_int. Ketika fungsi didefinisikan, dalam modul C, itu tidak disebut itu. Itu disebut _function. Ini akan menyebabkan kesalahan linker.

Untuk menghindari kesalahan itu, selama deklarasi fungsi, kami memberi tahu kompilator bahwa itu adalah fungsi yang dirancang untuk ditautkan, atau dikompilasi oleh, kompilator C:

extern "C" int function(int a);

Kompilator C ++ sekarang tahu cara mengimpor _functiondaripada _function_int, dan semuanya baik-baik saja.

Shachar Shemesh
sumber
1
@ShacharShamesh: Saya telah menanyakan ini di tempat lain, tetapi, bagaimana dengan menautkan di pustaka terkompilasi C ++? Ketika kompilator melangkah melalui dan menyusun kode saya yang memanggil salah satu fungsi dalam pustaka terkompilasi C ++, bagaimana ia tahu nama mana yang harus mangle atau berikan ke fungsi hanya dengan melihat deklarasi atau pemanggilan fungsinya? Bagaimana cara mengetahui bahwa di mana ia didefinisikan, ia diubah namanya menjadi sesuatu yang lain? Jadi harus ada metode name-mangling standar di C ++?
Engineer999
2
Setiap kompiler melakukannya dengan caranya yang khusus. Jika Anda mengkompilasi semuanya dengan kompiler yang sama, itu tidak masalah. Tetapi jika Anda mencoba menggunakan, katakanlah, pustaka yang dikompilasi dengan kompiler Borland, dari program yang Anda buat dengan kompiler Microsoft, yah ... semoga berhasil; Anda akan membutuhkannya :)
Tandai VY
6
@ Engineer999 Pernah bertanya-tanya mengapa tidak ada yang namanya pustaka C ++ portabel, tetapi mereka menentukan dengan tepat versi (dan tanda) apa dari kompiler (dan pustaka standar) yang harus Anda gunakan atau hanya mengekspor C API? Ini dia. C ++ adalah bahasa yang paling tidak portabel yang pernah ditemukan, sedangkan C adalah kebalikannya. Ada upaya dalam hal itu, tetapi untuk saat ini jika Anda menginginkan sesuatu yang benar-benar portabel, Anda akan tetap menggunakan C.
Voo
1
@Voo Nah, secara teori Anda harus dapat menulis kode portabel hanya dengan mengikuti standar misalnya -std=c++11, dan menghindari penggunaan apa pun di luar standar. Itu sama dengan mendeklarasikan versi Java (meskipun versi Java yang lebih baru kompatibel dengan versi sebelumnya). Ini bukan kesalahan standar orang menggunakan ekstensi spesifik compiler dan kode yang bergantung pada platform. Di sisi lain, Anda tidak dapat menyalahkan mereka, karena ada banyak hal (khususnya IO, seperti soket) yang hilang dalam standar. Panitia tampaknya perlahan mengejar itu. Koreksi saya jika saya melewatkan sesuatu.
mucaho
14
@mucaho: Anda sedang berbicara tentang portabilitas / kompatibilitas sumber. yaitu API. Voo berbicara tentang kompatibilitas biner , tanpa kompilasi ulang. Ini membutuhkan kompatibilitas ABI . Kompiler C ++ secara teratur mengubah ABI antar versi. (mis. g ++ bahkan tidak mencoba untuk memiliki ABI yang stabil. Saya berasumsi bahwa mereka tidak merusak ABI hanya untuk bersenang-senang, tetapi mereka tidak menghindari perubahan yang memerlukan perubahan ABI ketika ada sesuatu yang ingin diperoleh dan tidak ada cara baik lainnya untuk melakukannya.).
Peter Cordes
45

Ini bukan berarti bahwa mereka "tidak bisa", mereka tidak , pada umumnya.

Jika Anda ingin memanggil fungsi dalam pustaka C yang dipanggil foo(int x, const char *y), tidak ada gunanya membiarkan compiler C ++ Anda mengacaukannya foo_I_cCP()(atau apa pun, hanya membuat skema mangling di tempat di sini) hanya karena itu bisa.

Nama itu tidak akan menyelesaikan, fungsinya ada di C dan namanya tidak bergantung pada daftar tipe argumennya. Jadi compiler C ++ harus mengetahui hal ini, dan menandai fungsinya sebagai C untuk menghindari melakukan mangling.

Ingat bahwa fungsi C tersebut mungkin ada di pustaka yang kode sumbernya tidak Anda miliki, yang Anda miliki hanyalah biner dan header yang telah dikompilasi sebelumnya. Jadi compiler C ++ Anda tidak bisa melakukan "itu sendiri", itu tidak bisa mengubah apa yang ada di perpustakaan.

beristirahat
sumber
Ini adalah bagian yang saya lewatkan. Mengapa kompilator C ++ mengacaukan nama fungsi ketika ia melihat deklarasinya saja atau melihatnya dipanggil. Apakah itu bukan hanya nama fungsi mangle ketika melihat implementasinya? Ini akan lebih masuk akal bagi saya
Engineer999
13
@ Engineer999: Bagaimana Anda bisa memiliki satu nama untuk definisi dan satu lagi untuk deklarasi? "Ada fungsi bernama Brian yang bisa kamu panggil." "Oke, aku akan menelepon Brian." "Maaf, tidak ada fungsi bernama Brian." Ternyata namanya Graham.
Balapan Ringan di Orbit
Bagaimana dengan menautkan di pustaka terkompilasi C ++? Ketika kompilator melangkah melalui dan mengkompilasi kode kita yang memanggil salah satu fungsi dalam pustaka terkompilasi C ++, bagaimana ia tahu nama mana yang harus diatur atau diberikan ke fungsi hanya dengan melihat deklarasi atau pemanggilan fungsinya?
Engineer999
1
@ Engineer999 Keduanya harus menyetujui mangling yang sama. Jadi mereka melihat file header (ingat, ada sangat sedikit metadata di DLL asli - header adalah metadata itu), dan berkata "Ah, benar, Brian seharusnya benar-benar menjadi Graham". Jika ini tidak berhasil (mis. Dengan dua skema mangling yang tidak kompatibel), Anda tidak akan mendapatkan tautan yang benar dan aplikasi Anda akan gagal. C ++ memiliki banyak ketidakcocokan seperti ini. Dalam praktiknya, Anda kemudian harus secara eksplisit menggunakan nama rusak dan menonaktifkan mangling di sisi Anda (misalnya Anda memberi tahu kode Anda untuk mengeksekusi Graham, bukan Brian). Dalam latihan sebenarnya ... extern "C":)
Luaan
1
@ Engineer999 Saya mungkin salah, tetapi apakah Anda mungkin memiliki pengalaman dengan bahasa seperti Visual Basic, C # atau Java (atau bahkan Pascal / Delphi sampai batas tertentu)? Itu membuat interop tampak sangat sederhana. Dalam C dan terutama C ++, tidak ada artinya. Ada banyak konvensi pemanggilan yang perlu Anda hormati, Anda perlu tahu siapa yang bertanggung jawab atas memori apa, dan Anda harus memiliki file header yang memberi tahu Anda deklarasi fungsi, karena DLL itu sendiri tidak berisi cukup informasi - terutama dalam kasus pure C. Jika Anda tidak memiliki file header, biasanya Anda perlu mendekompilasi DLL untuk menggunakannya.
Luaan
32

apa yang salah dengan mengizinkan kompilator C ++ untuk merusak fungsi C juga?

Mereka tidak akan menjadi fungsi C lagi.

Fungsi bukan hanya tanda tangan dan definisi; bagaimana suatu fungsi bekerja sangat ditentukan oleh faktor-faktor seperti konvensi pemanggilan. "Application Binary Interface" yang ditentukan untuk digunakan pada platform Anda menjelaskan bagaimana sistem berbicara satu sama lain. C ++ ABI yang digunakan oleh sistem Anda menetapkan skema mangling nama, sehingga program pada sistem tersebut mengetahui cara memanggil fungsi di perpustakaan dan sebagainya. (Baca C ++ Itanium ABI untuk contoh yang bagus. Anda akan segera mengetahui mengapa itu perlu.)

Hal yang sama berlaku untuk C ABI di sistem Anda. Beberapa C ABI sebenarnya memiliki skema mangling nama (mis. Visual Studio), jadi ini bukan tentang "mematikan mangling nama" dan lebih banyak tentang beralih dari C ++ ABI ke C ABI, untuk fungsi tertentu. Kami menandai fungsi C sebagai fungsi C, yang terkait dengan C ABI (bukan C ++ ABI). Deklarasi harus sesuai dengan definisi (baik itu dalam proyek yang sama atau di beberapa perpustakaan pihak ketiga), jika tidak, deklarasi tidak ada gunanya. Tanpa itu, sistem Anda tidak akan tahu bagaimana menemukan / menjalankan fungsi-fungsi itu.

Adapun mengapa platform tidak mendefinisikan C dan C ++ ABI menjadi sama dan menyingkirkan "masalah" ini, itu sebagian bersifat historis - C ABI asli tidak cukup untuk C ++, yang memiliki ruang nama, kelas, dan operator yang kelebihan beban, semuanya yang entah bagaimana perlu direpresentasikan dalam nama simbol dengan cara yang ramah komputer - tetapi orang mungkin juga berpendapat bahwa membuat program C sekarang mematuhi C ++ tidak adil bagi komunitas C, yang harus menghadapi masalah yang jauh lebih rumit ABI hanya demi sebagian orang lain yang menginginkan interoperabilitas.

Balapan Ringan dalam Orbit
sumber
2
+int(PI/3), Tetapi dengan satu butir garam: aku akan sangat berhati-hati untuk berbicara tentang "C ++ ABI" ... AFAIK, ada upaya untuk mendefinisikan C ++ ABI, tapi tidak ada yang nyata de facto / de jure standar - sebagai isocpp.org/files /papers/n4028.pdf menyatakan (dan saya sepenuhnya setuju), kutipan, sungguh ironis bahwa C ++ sebenarnya selalu mendukung cara untuk mempublikasikan API dengan ABI biner yang stabil — dengan menggunakan subset C dari C ++ melalui “C ". . C++ Itanium ABIhanya itu - beberapa C ++ ABI untuk Itanium ... seperti yang dibahas di stackoverflow.com/questions/7492180/c-abi-issues-list
3
@vaxquis: Ya, bukan "C ++'s ABI", tetapi "a C ++ ABI" dengan cara yang sama seperti saya memiliki "kunci rumah" yang tidak berfungsi di setiap rumah. Sepertinya bisa lebih jelas, meskipun saya mencoba membuatnya sejelas mungkin dengan memulai dengan frase "C ++ ABI sedang digunakan oleh sistem Anda " . Saya menjatuhkan penjelas di ucapan selanjutnya agar singkatnya, tetapi saya akan menerima suntingan yang mengurangi kebingungan di sini!
Balapan Ringan di Orbit
1
AIUI C abi cenderung menjadi properti platform sementara C ++ ABI cenderung menjadi properti kompiler individual dan bahkan sering kali merupakan properti versi individual kompilator. Jadi jika Anda ingin menghubungkan antara modul yang dibangun dengan alat vendor yang berbeda, Anda harus menggunakan C abi untuk antarmuka.
plugwash
Pernyataan "fungsi yang terkoyak nama tidak akan menjadi fungsi C lagi" terlalu dilebih-lebihkan - sangat mungkin untuk memanggil fungsi yang terkoyak-nama dari vanilla C biasa jika nama yang rusak diketahui. Bahwa perubahan nama tidak membuatnya kurang patuh pada C ABI, yaitu tidak membuatnya menjadi fungsi C. Sebaliknya lebih masuk akal - kode C ++ tidak dapat memanggil fungsi C tanpa mendeklarasikannya sebagai "C" karena akan melakukan name mangling ketika mencoba untuk menautkan ke callee.
Peter - Pulihkan Monica
@ PeterA.Schneider: Ya, frasa judulnya dilebih-lebihkan. The keseluruhan sisa jawabannya berisi detail faktual yang bersangkutan.
Balapan Ringan di Orbit
21

MSVC sebenarnya tidak mengacaukan nama C, meski dengan cara yang sederhana. Kadang-kadang ditambahkan @4atau nomor kecil lainnya. Ini terkait dengan konvensi pemanggilan dan kebutuhan untuk pembersihan tumpukan.

Jadi premisnya cacat.

MSalters
sumber
2
Itu bukan nama mangling. Ini hanyalah konvensi penamaan khusus vendor (atau menghiasi nama) untuk mencegah masalah dengan executable yang ditautkan ke DLL yang dibangun dengan fungsi yang memiliki konvensi pemanggilan berbeda.
Peter
2
Bagaimana dengan persiapan dengan _?
OrangeDog
12
@ Peter: Secara harfiah hal yang sama.
Balapan Ringan di Orbit
5
@Frankie_C: "Penelepon membersihkan tumpukan" tidak ditentukan oleh standar C apa pun: tidak ada konvensi pemanggilan yang lebih standar daripada yang lain dari perspektif bahasa.
Ben Voigt
2
Dan dari perspektif MSVC, "konvensi panggilan standar" adalah apa yang Anda pilih /Gd, /Gr, /Gv, /Gz. (Artinya, konvensi pemanggilan standar adalah yang digunakan kecuali jika deklarasi fungsi secara eksplisit menetapkan konvensi pemanggilan.). Anda sedang memikirkan __cdeclyang merupakan konvensi panggilan standar default.
MSalters
13

Sangat umum untuk memiliki program yang sebagian ditulis dalam C dan sebagian ditulis dalam beberapa bahasa lain (seringkali bahasa assembly, tapi terkadang Pascal, FORTRAN, atau yang lainnya). Ini juga umum untuk memiliki program yang berisi komponen berbeda yang ditulis oleh orang berbeda yang mungkin tidak memiliki kode sumber untuk semuanya.

Pada kebanyakan platform, terdapat spesifikasi - sering disebut ABI [Application Binary Interface] yang menjelaskan apa yang harus dilakukan kompilator untuk menghasilkan fungsi dengan nama tertentu yang menerima argumen dari beberapa tipe tertentu dan mengembalikan nilai dari beberapa tipe tertentu. Dalam beberapa kasus, ABI dapat mendefinisikan lebih dari satu "konvensi pemanggil"; kompiler untuk sistem semacam itu sering kali menyediakan sarana untuk menunjukkan konvensi pemanggilan mana yang harus digunakan untuk fungsi tertentu. Misalnya, di Macintosh, kebanyakan rutinitas Toolbox menggunakan konvensi panggilan Pascal, jadi prototipe untuk sesuatu seperti "LineTo" akan menjadi seperti ini:

/* Note that there are no underscores before the "pascal" keyword because
   the Toolbox was written in the early 1980s, before the Standard and its
   underscore convention were published */
pascal void LineTo(short x, short y);

Jika semua kode dalam sebuah proyek dikompilasi menggunakan kompilator yang sama, tidak masalah apa nama kompilator yang diekspor untuk setiap fungsi, tetapi dalam banyak situasi akan diperlukan kode C untuk memanggil fungsi yang dikompilasi menggunakan alat lain dan tidak dapat dikompilasi ulang dengan kompilator saat ini [dan bahkan mungkin tidak dalam C]. Oleh karena itu, kemampuan untuk menentukan nama penaut sangat penting untuk penggunaan fungsi tersebut.

supercat
sumber
Ya, itulah jawabannya. Jika hanya C dan C ++ maka sulit untuk memahami mengapa dilakukan seperti itu. Untuk memahami kita harus meletakkan hal-hal dalam konteks cara lama menghubungkan secara statis. Menghubungkan statis tampaknya primitif bagi pemrogram Windows tetapi itu adalah alasan utama C tidak dapat mengubah nama.
pengguna34660
2
@ user34660: Bukan qutie. Itulah alasan mengapa C tidak dapat mengamanatkan keberadaan fitur yang implementasinya akan memerlukan nama yang dapat diekspor yang dapat dihapus, atau memungkinkan adanya beberapa simbol bernama serupa yang dibedakan oleh karakteristik sekunder.
supercat
apakah kita tahu bahwa ada upaya untuk "mengamanatkan" hal-hal seperti itu atau bahwa hal-hal seperti itu tersedia ekstensi untuk C sebelum C ++?
pengguna34660
@ user34660: Re "Penautan statis tampaknya primitif bagi pemrogram Windows ...", tetapi penautan dinamis terkadang tampak seperti PITA utama bagi orang yang menggunakan Linux, ketika menginstal program X (mungkin ditulis dalam C ++) berarti harus melacak dan menginstal versi tertentu dari perpustakaan yang Anda sudah memiliki versi berbeda di sistem Anda.
jamesqf
@jamesqf, ya, Unix tidak memiliki tautan dinamis sebelum Windows. Saya tahu sangat sedikit tentang penautan dinamis di Unix / Linux tetapi sepertinya itu tidak semulus yang bisa terjadi di sistem operasi pada umumnya.
pengguna34660
12

Saya akan menambahkan satu jawaban lain, untuk membahas beberapa diskusi tangensial yang terjadi.

C ABI (application binary interface) awalnya dipanggil untuk meneruskan argumen pada stack dalam urutan terbalik (yaitu - didorong dari kanan ke kiri), di mana pemanggil juga membebaskan penyimpanan stack. ABI modern sebenarnya menggunakan register untuk meneruskan argumen, tetapi banyak pertimbangan yang merusak kembali ke argumen stack asli yang diteruskan.

Pascal ABI yang asli, sebaliknya, mendorong argumen dari kiri ke kanan, dan callee harus melontarkan argumen. ABI C asli lebih unggul dari ABI Pascal asli dalam dua poin penting. Argumen push order berarti bahwa offset tumpukan dari argumen pertama selalu diketahui, memungkinkan fungsi yang memiliki jumlah argumen yang tidak diketahui, di mana argumen awal mengontrol berapa banyak argumen lain yang ada (ala printf).

Cara kedua di mana C ABI lebih unggul adalah perilaku jika penelepon dan penerima tidak setuju tentang berapa banyak argumen yang ada. Dalam kasus C, selama Anda tidak benar-benar mengakses argumen setelah yang terakhir, tidak ada hal buruk yang terjadi. Di Pascal, jumlah argumen yang salah muncul dari tumpukan, dan seluruh tumpukan rusak.

Windows 3.1 ABI asli didasarkan pada Pascal. Karena itu, ia menggunakan Pascal ABI (argumen dalam urutan kiri ke kanan, callee pops). Karena ketidakcocokan dalam nomor argumen dapat menyebabkan korupsi tumpukan, skema kerusakan dibentuk. Setiap nama fungsi dihancurkan dengan angka yang menunjukkan ukuran, dalam byte, dari argumennya. Jadi, pada mesin 16 bit, fungsi berikut (sintaks C):

int function(int a)

Hancur function@2, karena intlebarnya dua byte. Hal ini dilakukan agar jika deklarasi dan definisi tidak cocok, linker akan gagal menemukan fungsi daripada merusak tumpukan pada waktu proses. Sebaliknya, jika program menautkan, maka Anda bisa yakin jumlah byte yang benar dikeluarkan dari tumpukan di akhir panggilan.

32 bit Windows dan selanjutnya gunakan stdcall ABI sebagai gantinya. Mirip dengan Pascal ABI, hanya saja urutan push seperti di C, dari kanan ke kiri. Seperti Pascal ABI, nama mangling mengubah ukuran byte argumen menjadi nama fungsi untuk menghindari korupsi tumpukan.

Tidak seperti klaim yang dibuat di tempat lain di sini, C ABI tidak merusak nama fungsi, bahkan di Visual Studio. Sebaliknya, fungsi mangling yang didekorasi dengan stdcallspesifikasi ABI tidak unik untuk VS. GCC juga mendukung ABI ini, bahkan saat mengompilasi untuk Linux. Ini digunakan secara luas oleh Wine , yang menggunakan loadernya sendiri untuk memungkinkan penautan waktu proses dari binari terkompilasi Linux ke DLL yang dikompilasi Windows.

Shachar Shemesh
sumber
9

Compiler C ++ menggunakan name mangling untuk memungkinkan nama simbol unik untuk fungsi yang kelebihan beban yang tanda tangannya akan sama. Ini pada dasarnya mengkodekan jenis argumen juga, yang memungkinkan polimorfisme pada tingkat berbasis fungsi.

C tidak memerlukan ini karena tidak memungkinkan untuk kelebihan beban fungsi.

Perhatikan bahwa mangling nama adalah salah satu (tapi tentu saja bukan satu-satunya!) Alasan bahwa seseorang tidak dapat mengandalkan 'C ++ ABI'.

dgrine
sumber
8

C ++ ingin dapat berinteraksi dengan kode C yang tertaut dengannya, atau yang ditautkan dengannya.

C mengharapkan nama fungsi yang tidak dirusak nama.

Jika C ++ merusaknya, ia tidak akan menemukan fungsi non-rusak yang diekspor dari C, atau C tidak akan menemukan fungsi yang diekspor C ++. C linker harus mendapatkan nama yang diharapkannya sendiri, karena tidak tahu itu berasal dari atau menuju ke C ++.

Yakk - Adam Nevraumont
sumber
3

Mengolah nama-nama fungsi dan variabel C akan memungkinkan tipenya diperiksa pada waktu tautan. Saat ini, semua (?) Implementasi C memungkinkan Anda untuk mendefinisikan variabel dalam satu file dan menyebutnya sebagai fungsi di file lain. Atau Anda dapat mendeklarasikan fungsi dengan tanda tangan yang salah (misalnya void fopen(double), lalu memanggilnya.

Saya mengusulkan skema untuk hubungan tipe-aman dari variabel dan fungsi C melalui penggunaan mangling pada tahun 1991. Skema ini tidak pernah diadopsi, karena, seperti yang telah disebutkan di sini, ini akan menghancurkan kompatibilitas ke belakang.

Diomidis Spinellis
sumber
1
Maksud Anda "izinkan jenis mereka diperiksa pada waktu tautan ". Jenis yang diperiksa pada waktu kompilasi, tetapi menghubungkan dengan nama unmangled tidak dapat memeriksa apakah deklarasi digunakan dalam unit kompilasi yang berbeda setuju. Dan jika mereka tidak setuju, itu adalah sistem build Anda yang pada dasarnya rusak dan perlu diperbaiki.
cmaster