有没有一种内联的方式来混合c和c++原型

Is there an inline way to mix c and c++ prototypes?

本文关键字:混合 方式 原型 c++ 一种 有没有      更新时间:2023-10-16

我想要一种内联方式来指定哪些原型应该包含在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);

目前我正在做:

#ifdef__cplusplus外部"C"{#endif….C标头。。#ifdef__cplusplus}….C++标头。。。#endif

但是它非常不方便,因为同一功能的过载在不同的地方。我可以有两个不同的头文件,但这也很痛苦。因此,我正在寻找一个像我上面提出的内联解决方案。有人知道这样做的方法吗?

这比你想象的要容易。

#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))

当然,您可以像您的示例一样使用宏这样的函数:

#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));

现在,如果你把头编译成C++,你会得到这三个,但如果你编译成C,你只会得到一个。如果您想在两者之间共享一个库,那么在为C++编译时,需要向C函数添加一些extern "C"限定符@MarkLakata的回答显示了一种可能的方式。

通常的方法是用最明显的方式编写:

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所指出的,在项目范围的标题中,您还需要

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

并且需要用CCD_ 2来修饰C可调用函数。

很明显,您可以滥用预处理器来破解您的问题,但为什么要这样做呢?就我个人而言,如果我使用C++,我宁愿键入mylst.insert(foop, 1);而不是ArrayList_insert(mylst, foop, 1);。换句话说,我认为使用C风格来调用重载函数没有什么好处,但混合您作为代码作者创建的函数调用的风格也不太好。

我会创建一个ArrayList类,该类的成员与C结构中的成员相同,当你需要将类与C函数接口时,如果可能的话,创建一个浅拷贝并将其传递给C函数,然后将该结构中的信息复制回你的类中。

另一种选择是将结构封装在C++类中,并将其用于C接口函数。

否则,您可能会尝试让类继承C结构,假设该结构的标记没有命名为ArrayList,并且该结构的typedef在C++接口中不可见。然后,您可以从成员函数中直接传递this指针,就好像它是实际的C结构一样。我不确定这个方法在所有情况下都是可移植的,所以如果可能的话,我会实现前一个想法,即使它确实需要来回复制数据。

所有的想法都避免了代码重复,C++接口看起来更像C++代码,而不是C函数和C++函数重载的糟糕混合。此外,接口在某种程度上是分开的。也不需要额外的头文件,因为C函数可以像往常一样封装在外部"C"块中:

#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

如果你真的想摆脱样板,并且你愿意使用预处理器来完成,那么就继续写模式吧。你的一般模式看起来像

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

所以你可以制作一个宏,

#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

这是因为普通函数声明不能包含未用括号括起来的逗号。如果您希望它与模板(使用逗号分隔的模板参数)一起工作,那么您可以将C99、C++11中支持的可变宏以及这些标准之前的各种编译器作为扩展。

#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

现在,只要C声明不包含裸逗号,这就可以工作,这意味着不应该在一个声明中声明多个对象。我称它为C_PORTABLE_FUNCTION_SET,以强调它主要用于函数声明是安全的,但请注意,您还需要在extern C中声明C可访问的对象。共享的struct定义根本不应该受到保护;它们受到C++POD概念的保护,并且不带有语言链接。

用法:

#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);
)

我想我自己不会这么做,但这似乎足够安全,可以成为惯用语。