首页 文章

是否有内联方式来混合c和c原型?

提问于
浏览
10

我想要一种内联方式来指定哪些原型应该包含在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
extern "C" {
#endif

....C HEADERS..

#ifdef __cplusplus
}

....C++ HEADERS...

#endif

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

5 回答

  • 11

    它比你想象的容易 .

    #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
    

    使用这种类型的 Headers :

    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))
    
  • 1

    当然,通过使用类似函数的宏,你几乎可以像你的例子那样做:

    #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,那么'll get all three, but if you compile as C, you' ll只会得到一个 . 如果要在两者之间共享一个库,则在编译C时需要向C函数添加一些 extern "C" 限定符 . @MarkLakata的回答显示了一种可能的方式 .

  • 3

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

    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指出的那样,你还需要在项目范围的 Headers 中,

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

    你需要用 EXTERN_C 来装饰C-callable函数 .

  • 14

    你显然可以滥用预处理器来破解你所要求的内容,但为什么呢?就个人而言,如果我使用C,我宁愿输入 mylst.insert(foop, 1); 而不是 ArrayList_insert(mylst, foop, 1); . 换句话说,我认为使用C样式调用重载函数没什么好处,但是混合代码作者创建的函数调用样式也不是很完美 .

    我将创建一个与C结构中的成员相同的ArrayList类,并且只要需要将类与C函数接口,就可以创建一个浅表副本并将其传递给C函数,然后从中复制信息 . 那个结构回到你的 class .

    另一种方法是将结构包装在C类中,并将其用于C接口函数 .

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

    所有的想法都避免了代码重复,C接口看起来更像C代码,而不是C函数和C函数重载的错误混合 . 另外,接口在某种程度上是分开的 . 不需要额外的头文件,因为C函数可以像往常一样包装在extern“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
    
  • 1

    如果你真的想摆脱样板并且你愿意使用预处理器去做,那么就继续写下模式 . 你看起来的一般模式

    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声明不包含裸逗号,这就行了,这意味着你不应该_1158982_称它为 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);
    )
    

    我不认为我自己会这样做,但似乎足够安全,成为惯用语 .

相关问题