Saya memiliki fungsi C yang ingin saya panggil dari C ++. Saya tidak bisa menggunakan " extern "C" void foo()
" jenis pendekatan karena fungsi C gagal dikompilasi menggunakan g ++. Tapi dikompilasi dengan baik menggunakan gcc. Ada ide bagaimana memanggil fungsi dari C ++?
90
g++
pesan kesalahanvoid valid_in_C_but_not_in_CPlusPlus(size_t size) { char variable_length_array[size]; }
void f(void *pv) { int *pi = pv; *pi = 42; }
Jawaban:
Kompilasi kode C seperti ini:
gcc -c -o somecode.o somecode.c
Kemudian kode C ++ seperti ini:
g++ -c -o othercode.o othercode.cpp
Kemudian tautkan keduanya, dengan linker C ++:
g++ -o yourprogram somecode.o othercode.o
Anda juga harus memberi tahu compiler C ++ bahwa header C akan muncul saat Anda menyertakan deklarasi untuk fungsi C. Jadi
othercode.cpp
dimulai dengan:extern "C" { #include "somecode.h" }
somecode.h
harus berisi sesuatu seperti:#ifndef SOMECODE_H_ #define SOMECODE_H_ void foo(); #endif
(Saya menggunakan gcc dalam contoh ini, tetapi prinsipnya sama untuk semua kompiler. Buat secara terpisah sebagai C dan C ++, masing-masing, lalu tautkan bersama.)
sumber
extern "C"
di header dengan#ifdef __cplusplus
.Izinkan saya mengumpulkan potongan-potongan dari jawaban dan komentar lain, untuk memberi Anda contoh dengan kode C dan C ++ yang dipisahkan dengan rapi:
Bagian C:
foo.h :
#ifndef FOO_H #define FOO_H void foo(void); #endif
foo.c
#include "foo.h" void foo(void) { /* ... */ }
Kompilasi ini dengan
gcc -c -o foo.o foo.c
.Bagian C ++:
bar.cpp
extern "C" { #include "foo.h" //a C header, so wrap it in extern "C" } void bar() { foo(); }
Kompilasi ini dengan
g++ -c -o bar.o bar.cpp
Dan kemudian tautkan semuanya:
g++ -o myfoobar foo.o bar.o
Rasional: Kode C harus kode C biasa, bukan
#ifdef
untuk "mungkin suatu hari nanti saya akan memanggil ini dari bahasa lain". Jika beberapa programmer C ++ memanggil fungsi C Anda, itu masalah mereka bagaimana melakukannya, bukan milik Anda. Dan jika Anda adalah programmer C ++, maka header C mungkin bukan milik Anda dan Anda tidak boleh mengubahnya, jadi penanganan nama fungsi yang tidak berubah (yaituextern "C"
) termasuk dalam kode C ++ Anda.Anda dapat, tentu saja, menulis sendiri header C ++ praktis yang tidak melakukan apa pun kecuali menggabungkan header C ke dalam
extern "C"
deklarasi.sumber
Saya setuju dengan jawaban Prof. Falken , namun setelah komentar Arne Mertz saya ingin memberikan contoh yang lengkap (bagian terpenting adalah
#ifdef __cplusplus
):somecode.h
#ifndef H_SOMECODE #define H_SOMECODE #ifdef __cplusplus extern "C" { #endif void foo(void); #ifdef __cplusplus } #endif #endif /* H_SOMECODE */
somecode.c
#include "somecode.h" void foo(void) { /* ... */ }
othercode.hpp
#ifndef HPP_OTHERCODE #define HPP_OTHERCODE void bar(); #endif /* HPP_OTHERCODE */
othercode.cpp
#include "othercode.hpp" #include "somecode.h" void bar() { foo(); // call C function // ... }
Kemudian Anda mengikuti instruksi Prof. Falken untuk menyusun dan menautkan.
Ini berfungsi karena saat mengompilasi dengan
gcc
, makro__cplusplus
tidak ditentukan, jadi header yangsomecode.h
disertakansomecode.c
seperti ini setelah pemrosesan awal:void foo(void);
dan ketika kompilasi dengan
g++
, maka__cplusplus
yang didefinisikan, dan header termasuk dalamothercode.cpp
sekarang seperti itu:extern "C" { void foo(void); }
sumber
#ifdef __cplusplus
di kode C. Kode C adalah level yang lebih rendah, dan tidak perlu repot jika mungkin dipanggil dari kode C ++ suatu hari nanti. Imo yang#ifdef
penggunaannya hanya dalam kode C ++ jika Anda ingin memberikan header pengikatan C untuk pustaka yang ditulis dalam C ++, bukan sebaliknya.Jawaban ini diinspirasi oleh kasus di mana alasan Arne benar. Vendor menulis pustaka yang pernah mendukung C dan C ++; namun, versi terbaru hanya mendukung C. Arahan sisa berikut yang tersisa di kode menyesatkan:
#ifdef __cplusplus extern "C" { #endif
Ini menghabiskan waktu beberapa jam untuk mencoba mengkompilasi dalam C ++. Cukup menelepon C dari C ++ jauh lebih mudah.
Konvensi ifdef __cplusplus melanggar prinsip tanggung jawab tunggal. Kode yang menggunakan konvensi ini mencoba melakukan dua hal sekaligus:
Ini seperti mencoba menulis dalam bahasa Inggris Amerika dan Inggris pada saat yang bersamaan. Ini tidak perlu membuang kunci pas #ifdef __thequeensenglish #elif __yankeeenglish wrench #else alat yang tidak berguna yang membuat kode lebih sulit dibaca #endif ke dalam kode.
Untuk kode sederhana dan pustaka kecil, konvensi ifdef __cplusplus dapat berfungsi; Namun, untuk perpustakaan yang kompleks, yang terbaik adalah memilih satu bahasa atau yang lain dan tetap menggunakannya. Mendukung salah satu bahasa akan membutuhkan lebih sedikit perawatan daripada mencoba mendukung keduanya.
Ini adalah catatan modifikasi yang saya buat pada kode Arne agar dapat dikompilasi di Ubuntu Linux.
foo.h :
#ifndef FOO_H #define FOO_H void foo(void); #endif
foo.c
#include "foo.h" #include <stdio.h> void foo(void) { // modified to verify the code was called printf("This Hello World was called in C++ and written in C\n"); }
bar.cpp
extern "C" { #include "foo.h" //a C header, so wrap it in extern "C" } int main() { foo(); return(0); }
Makefile
# -*- MakeFile -*- # dont forget to use tabs, not spaces for indents # to use simple copy this file in the same directory and type 'make' myfoobar: bar.o foo.o g++ -o myfoobar foo.o bar.o bar.o: bar.cpp g++ -c -o bar.o bar.cpp foo.o: foo.c gcc -c -o foo.o foo.c
sumber