有没有一种内联的方式来混合c和c++原型
Is there an inline way to mix c and c++ prototypes?
我想要一种内联方式来指定哪些原型应该包含在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);
)
我想我自己不会这么做,但这似乎足够安全,可以成为惯用语。
- 如何在c++中为模板函数实例创建快捷方式
- 在c代码之间共享数据的最佳方式
- 在C++中将函数压缩为两种方式
- 以螺旋方式打印矩阵的程序.(工作不好)
- 混合组合和继承的C++问题
- 在混合代码库中将C转换为C++时出现许多包含错误
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- 创建引用向量的优雅方式
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 使用QQuickFramebufferObject时同步数据的最佳方式是什么
- 不同/较旧的处理器运行c++代码的方式是否不同
- 从嵌套在std::映射中的std::列表中删除元素的最佳方式
- D3D11-将混合权重和索引传递到顶点着色器
- 如果条件为TRUE(最佳方式?),则在do while循环中后置增量
- 重载方法的方式会在使用临时调用时生成编译器错误
- C++以迭代方式搜索混合类型地图
- 以双向方式混合目标C++和C++
- 有没有一种内联的方式来混合c和c++原型
- 通过boost::asio传输混合unicode和单字节字符的最佳方式
- 异常和错误代码:以正确的方式混合它们