2013-07-01 36 views
10

C++ ile hangi prototiplerin dahil edilmesi gerektiğini belirten satır içi bir yol istiyorum. Örneğin: c ve C++ prototiplerini karıştırmanın bir yolu var mı?

 
     void ArrayList_insert(ArrayList *arrlst, void *data, int i); 
IS_CPP void ArrayList_insert(ArrayList *arrlst, char *data, int i); 
IS_CPP void ArrayList_insert(ArrayList *arrlst, Buffer *data, int i); 

şu anda yapıyorum:

 
#ifdef __cplusplus 
extern "C" { 
#endif 

....C HEADERS.. 

#ifdef __cplusplus 
} 

....C++ HEADERS... 

#endif 

ama aynı işlevin aşırı yükler farklı yerlerde olduğu için onun çok sakıncalı. Sadece 2 farklı başlık dosyası alabilirim, ama bu da bir acı. Bu nedenle, yukarıda önerdiğim gibi bir satır içi çözüm arıyorum. Bunu yapmanın bir yolu bilen var mı? Eğer olarak derlemek eğer üçünü alırsınız, sen C++ olarak başlık derlemek Şimdi eğer

#ifdef __cplusplus 
#define IS_CPP(x) x 
#else 
#define IS_CPP(x) 
#endif 

     void ArrayList_insert(ArrayList *arrlst, void *data, int i); 
IS_CPP(void ArrayList_insert(ArrayList *arrlst, char *data, int i)); 
IS_CPP(void ArrayList_insert(ArrayList *arrlst, Buffer *data, int i)); 

ama:

cevap

14

Düşündüğünüzden daha kolay. Başlığın Bu tür

#ifdef __cplusplus 
#define IS_C(x) extern "C" x ; 
#define IS_CPP(x) x ; 
#else 
#define IS_C(x) x ; 
#define IS_CPP(x) 
#endif 

:

IS_C (void ArrayList_insert(ArrayList *arrlst, void *data, int i)) 
IS_CPP (void ArrayList_insert(ArrayList *arrlst, char *data, int i)) 
IS_CPP (void ArrayList_insert(ArrayList *arrlst, Buffer *data, int i)) 
+0

bu, c ile derlendiğinde bir hataya neden olur çünkü c işlevi aşırı yüklenmeyi desteklemez. – chacham15

+0

chacham15 - Haklısınız. Cevabı ben çözdüm, çünkü sorumu yanlış anladım. –

+0

Artık @Carl Norum'un cevabıyla eşdeğer. Carl'ın cevabı hariç, – chacham15

11

Tabii, bir fonksiyon benzeri makro kullanarak neredeyse örnekteki gibi yapabiliriz C, sadece bir tane alacaksın. Bu ikisi arasında tek bir kitaplık paylaşmak isterseniz, C++ için derlerken C işlevine extern "C" niteleyici eklemeniz gerekir. @ MarkLakata'nın cevabı, olası bir yolu göstermektedir.

+0

+1 Ancak, sondaki yakın paren olmadan bunu yapmak için herhangi bir yolu var mı? (Sadece biraz eksantrik, sry) – chacham15

+0

Sanmıyorum, hayır. –

+0

-1, bu gerekli dil bağlantısı eksik. – Potatoswatter

1

Açıkçası ne istediğini araya kesmek için önişlemci kötüye kullanabilirler ama neden yapıyorsun? Şahsen C++ kullanıyor olsaydım ArrayList_insert(mylst, foop, 1); yerine mylst.insert(foop, 1); yazmayı tercih ederim. Diğer bir deyişle, aşırı yüklenmiş fonksiyonları çağırmak için C stilini kullanmanın yararından çok fayda görmüyorum, ancak kod yazıcısı olarak yarattığınız işlevlerin stillerini karıştırmak da güzel değil.

C yapısıyla aynı üyelere sahip olan ve C işlevleriyle sınıfınızı arabiriminize bağlamanız, mümkünse sığ bir kopya oluşturmanız ve bunu C işlevine iletmeniz gereken bir ArrayList sınıfı hazırlıyorum. Bu yapıdaki bilgileri tekrar sınıfınıza kopyalayın. Bir alternatif, bir C++ sınıfında yapının sarılması ve C arayüz fonksiyonları için kullanılmasıdır.

Aksi takdirde, yapının etiketinin ArrayList olarak adlandırılmadığı ve yapının yazımının C++ arabiriminden görünmediği varsayılarak, sınıfı C yapısını miras bırakmayı deneyebilirsiniz. O zaman bu işaretçiyi, gerçek C yapısı gibi, üye işlevinin içinden doğrudan iletebilirsiniz. Bu yöntemin her durumda taşınabilir olduğundan emin değilim, bu yüzden eğer veriyi ileri geri kopyalamayı gerektirse bile, eğer mümkün ise eski fikri uygularım.

Tüm fikirler kod yinelemesinden kaçınır ve C++ arabirimi C işlevleri ve C++ işlevi aşırı yüklenmesinin kötü karışımı yerine C++ kodu gibi görünür. Ek olarak, arayüzler biraz ayrı tutulur.Ek başlık dosyaları gereklidir ya C fonksiyonları her zamanki gibi extern "C" blokta sarılmış edilebilir:

#ifdef __cplusplus 
extern "C" { 
#endif 

struct array_list_tag { 
    ... 
}; 

/* C functions here */ 

#ifdef __cplusplus 
} /* extern "C" */ 

class ArrayList ... 
#else /* !__cplusplus */ 
typedef struct array_list_tag ArrayList; 
#endif 
+0

"Tüm fikirler kod çoğaltımını önler" Tam olarak. Bir örnek kullanım örneği, C++ ile bir kütüphane yazmaktır. Bu, C ile büyük ölçüde entegre edilmiş demektir. Aşırı fonksiyonlarını çağırmak gibi bir şeysiniz, fakat gerekli olanı aramak için entegre olduğun C'nin bir yolu olmalı. fonksiyonları da vardır.Yapıları sınıflar halinde sarmalamak veya tam tersi kod çoğaltma miktarını arttırır ve – chacham15

+0

platformunda kodlama stilinde bir tutarsızlık eklersiniz. Yani C'nin her aşırı yüklenmiş fonksiyonu arayabilmesi gerektiğini mi söylüyorsunuz? Ardından sadece OP için ArrayList_insert yerine, yalnızca ArrayList_insertBuffer, ArrayList_insertString, ArrayList_insertRawData, vs.? Peki, C++ arayüzü en azından eşleşecek ... Sınıflardaki yapıları sarmalamak için muhtemelen haklısınız. C++ sınıf verilerine erişebilmek için C++ ile bir fonksiyon gerektiren C++ standardında bir şey olduğundan emin olabilirim, çünkü miras, sanal fonksiyonlar ve karıştırma sınıflarıyla birlikte gelen diğer tüm uyarılar olmadığı sürece C. –

3

zamanki yaklaşım sadece en belirgin bir şekilde yazmaktır:

void ArrayList_insert(ArrayList *arrlst, void *data, int i); 
#ifdef __cplusplus 
void ArrayList_insert(ArrayList *arrlst, char *data, int i); 
void ArrayList_insert(ArrayList *arrlst, Buffer *data, int i); 
#endif /* __cplusplus */ 
@ chacham15 olarak

#ifdef __cplusplus 
#define EXTERN_C extern "C" 
#endif /* __cplusplus */ 

, ayrıca bir proje çapında başlığında, gerek, işaret ve EXTERN_C C-çağrılabilir fonksiyonu dekore gerekir.

+0

onun kadar basit değil, IMO gerçekten kludgy görünmesini sağlar c fonksiyonu için #ifdef __cplusplus extern "c" # endif' beyanı eksik. – chacham15

+0

@ Chacham15: başka bir yerde yorumda bulunduğunuzda, #ifdef __cplusplus #define IS_C extern "C" #else #define IS_C# endif' veya benzeri ("EXTERN_C" gibi bir ad öneririm) bir kez yapılabilir. Pete's yaklaşımı görünüyor çok temiz ... bir makroda her satır sarmaktan daha güzel, çoğaltır ')), ya makro içinde noktalı virgül sahip ya da görsel olarak her satır eksik. –

1

Eğer kazandan gerçekten kurtulmak istiyorsanız ve bunu yapmak için önişlemci kullanmaya hazırsanız, o zaman devam edin ve deseni yazın.

extern "C" { 
    void C_accessible_declaration(); // this is all C sees 
} 

void Cxx_accessible_declaration_1(int); 
void Cxx_accessible_declaration_1(long); 

Yani bir makro yapabilir gibi sahip genel desen sıradan bir fonksiyon beyan parantez içine alınmış değil virgül içeremez çünkü bu işler

#ifdef __cplusplus 
# define C_PORTABLE_FUNCTION_SET(C_DECLS, CXX_DECLS) \ 
     extern "C" { C_DECLS } \ 
     CXX_DECLS 
#else 
# define C_PORTABLE_FUNCTION_SET(C_DECLS, CXX_DECLS) \ 
     C_DECLS 
#endif 

görünüyor. Şablonlarla çalışmak istiyorsanız (virgülle ayrılmış şablon parametreleriyle), C99, C++ 11'de desteklenen variadic makroları ve bu standartlardan önce bir uzantı olarak çeşitli derleyicileri kullanabilirsiniz.

#ifdef __cplusplus 
# define C_PORTABLE_FUNCTION_SET(C_DECLS, ...) \ 
     extern "C" { C_DECLS } \ 
     __VA_ARGS__ 
#else 
# define C_PORTABLE_FUNCTION_SET(C_DECLS, ...) \ 
     C_DECLS 
#endif 

Şimdi bu C bildirimleri tek bildiriminde birden çok nesne beyan etmemelidir anlamına çıplak virgül içermez sürece çalışır. Fonksiyon bildirimleriyle birlikte kullanımının daha güvenli olduğunu vurgulamak için C_PORTABLE_FUNCTION_SET'u aradım, ancak extern C içerisinde C-erişilebilir nesneler de bildirmeniz gerektiğini unutmayın. Paylaşılan struct tanımları hiç korunmamalıdır; C++ POD konsepti ile korunurlar ve dil bağlantısı yürütmezler.

Kullanımı:

#ifdef __cplusplus 
template< typename T, typename U > 
class Buffer { // still use #ifdef for the general case 
    ... 
}; 
#endif 

C_PORTABLE_FUNCTION_SET (
     void ArrayList_insert(ArrayList *arrlst, void *data, int i); 
, /* C++ */ 
     void ArrayList_insert(ArrayList *arrlst, char *data, int i); 

     template< typename T, typename U > 
     void ArrayList_insert(ArrayList *arrlst, Buffer< T, U > &data, int i); 
) 

Ben bu kendim yapmak sanmıyorum ama deyimsel olmak için yeterince güvenli görünüyor.

İlgili konular