Menggunakan pustaka C ++ dalam kode C.

102

Saya memiliki pustaka C ++ yang menyediakan berbagai kelas untuk mengelola data. Saya memiliki kode sumber untuk perpustakaan.

Saya ingin memperluas C ++ API untuk mendukung pemanggilan fungsi C sehingga perpustakaan dapat digunakan dengan kode C dan kode C ++ pada saat yang bersamaan.

Saya menggunakan rantai alat GNU (gcc, glibc, dll), jadi dukungan bahasa dan arsitektur tidak menjadi masalah.

Apakah ada alasan mengapa hal ini secara teknis tidak memungkinkan?

Apakah ada gotcha yang perlu saya waspadai?

Apakah ada sumber daya, kode contoh dan / atau dokumentasi yang tersedia tentang ini?


Beberapa hal lain yang saya temukan:

  1. Gunakan perintah berikut untuk menggabungkan header C ++ Anda yang perlu digunakan oleh kode C.

#ifdef __cplusplus
extern "C" {  
#endif  
//  
// Code goes here ...  
//  
#ifdef __cplusplus  
} // extern "C"  
#endif
  1. Pertahankan antarmuka C ++ "asli" di file header terpisah yang tidak disertakan oleh C. Pikirkan prinsip PIMPL di sini. Menggunakan #ifndef __cplusplus #errorbarang membantu di sini untuk mendeteksi kegilaan.
  2. Hati-hati dengan pengenal C ++ sebagai nama dalam kode C.
  3. Enum memiliki ukuran yang bervariasi antara compiler C dan C ++. Mungkin bukan masalah jika Anda menggunakan rantai alat GNU, tapi tetap berhati-hatilah.
  4. Untuk struct, ikuti formulir berikut agar C tidak bingung.

    typedef struct X { ... } X
  5. Kemudian gunakan pointer untuk meneruskan objek C ++, mereka hanya harus dideklarasikan di C sebagai struct X di mana X adalah objek C ++.

Semua ini adalah milik seorang teman yang merupakan ahli sihir di C ++.

Misha M
sumber
5
Agak terlambat, tapi saya menulis howto kecil tentang C wrapper untuk C ++: teddy.ch/c++_library_in_c
Teddy

Jawaban:

69

Ya, ini pasti mungkin. Anda perlu menulis lapisan antarmuka dalam C ++ yang mendeklarasikan fungsi dengan extern "C":

extern "C" int foo(char *bar)
{
    return realFoo(std::string(bar));
}

Kemudian, Anda akan memanggil foo()dari modul C Anda, yang akan meneruskan panggilan ke realFoo()fungsi yang diimplementasikan di C ++.

Jika Anda perlu mengekspos kelas C ++ lengkap dengan anggota data dan metode, Anda mungkin perlu melakukan lebih banyak pekerjaan daripada contoh fungsi sederhana ini.

Greg Hewgill
sumber
Haruskah extern "C"ditempatkan hanya dalam deklarasi (dan bukan dalam definisi)? Karena Anda menyebutkan "lapisan yang mendeklarasikan fungsi" tetapi kode sampel Anda juga merupakan definisi. Dengan kata lain, haruskah kita menempatkannya di file header atau file sumber? (Atau keduanya?)
kyriakosSt
@KyrSt: Jika Anda memiliki file header dengan deklarasi fungsi, setidaknya Anda harus meletakkannya di extern "C"sana. Kompiler Anda akan memberi tahu Anda jika Anda juga harus meletakkannya pada definisi.
Greg Hewgill
23

C ++ FAQ Lite: "Cara mencampur kode C dan C ++" .

Beberapa gotcha dijelaskan dalam jawaban atas pertanyaan-pertanyaan ini:

  • [32.8] Bagaimana cara mengirimkan objek kelas C ++ ke / dari fungsi C?
  • [32.9] Dapatkah fungsi C saya secara langsung mengakses data dalam sebuah objek kelas C ++?
Alex B
sumber
12

Gotcha utama: pengecualian tidak dapat ditangkap di C. Jika ada kemungkinan pengecualian muncul dalam kode C ++, tulis kode C atau pembungkus C ++ Anda dengan sangat hati-hati. Sebaliknya, pengecualian seperti mekanisme (yaitu, longjump) dalam kode C (seperti yang ditemukan dalam berbagai bahasa skrip) tidak diperlukan untuk memanggil destruktor untuk objek C ++ pada tumpukan.

ejgottl.dll
sumber
2
Poin bagus tentang panggilan longjump. Meskipun saya tidak menggunakannya secara langsung, kerangka kerja pengujian yang saya gunakan menerapkannya. Sesuatu yang perlu diingat. Terima kasih
Misha M
3

Anda dapat mencampur kode C / C ++. Jika main () berfungsi di C ++, maka Anda hanya perlu memastikan fungsi c Anda dideklarasikan

extern "C"

Jika utama Anda adalah C, maka Anda mungkin baik-baik saja kecuali untuk variabel statis. Setiap konstruktor dengan variabel statis Anda seharusnya dipanggil sebelum main () start. Ini tidak akan terjadi jika C adalah utama Anda. Jika Anda memiliki banyak variabel statis, hal terbaik yang harus dilakukan adalah mengganti variabel statis dengan lajang.

David Nehme
sumber