2015-02-11 38 views
2

比方说,我有一个C++头文件foo.hpp如何在C中实现在C++名称空间中声明的函数?

namespace foo { 
    int bar(int); 
} 

,因为它需要只能从命名空间foo访问我不能使用extern "C"

是否有一个便携式(或相对便携)的方式来声明foo::bar在C文件foo.c,以便它将链接任何使用从C++ foo::bar

我知道,有一个特定的编译器在特定的系统,我可以找出如何foo::bar是错位的,做这样的事情在foo.c

int ZN3foo3barEi(int x) { /* ... */ } 

但这既不便携,也不可读。

+1

不,你有一个'extern“C”foo_bar“转发到'foo :: bar'或者从命名空间foo和'extern'C”foo_bar'删除该条(实现该功能) – 2015-02-11 18:06:55

+0

你是什么是指“转发”? – Matt 2015-02-11 18:13:06

+0

转发:'extern“C”int foo_bar(int x){return foo :: bar(x); }' – 2015-02-11 18:18:25

回答

1

包装会被接受吗?

namespace foo { 
    int bar(int); 
    } 
extern "C" int callable_from_c(int f) { 
    return foo::bar(f); 
    } 
+0

这与我正在做的事情相反。但无论如何,封装将是我的备份计划。 – Matt 2015-02-11 18:14:37

+1

明白了。我知道你希望有更清洁的东西,并且我正在自己看着你想要的东西(手指交叉)。 – user590028 2015-02-11 18:37:19

3

extern "C"可以嵌套(其实,这跟<cstdio>头通常如何工作!),所以你可以做到以下几点:

/* C++ code */ 
namespace foo { 
    extern "C" { 
     int bar(int); 
    } 
} 

之后,你只需要实现它在C作为平时:

/* C code */ 
int bar(int x) { 
    return -x; /* or whatever */ 
} 

不幸的是,如果有一个命名冲突(比如,如果你有两个foo::barbaz::bar),除非它们具有相同的功能,否则您将无法拥有它们。

+0

这就是我说的“它只需要从'foo'命名空间访问'。不应该有任何全局名称'bar',甚至可能与C中的其他名称发生冲突。命名空间的全部要点是为了防止名称冲突。 – Matt 2015-02-11 18:12:03

+0

@Matt:在这种情况下,不需要---你需要一个包装函数。请参阅user590028的答案。 – 2015-02-11 18:12:49

+0

这只是一个带有“C”连接的函数的前向声明 - 我怀疑它会按预期工作 – 2015-02-11 18:13:57

0

被迫您的备份计划(使用一个包装函数),原因如下:C++支持的功能超载,并通过这个原因,你可以有bar不同的实现(与不同的指纹,甚至兼容)而你只能在C中实现一个实现。如果你从C中调用它们,哪一个C++可能会匹配bar?如果你在C++中有bar(int)bar(long),而你想从C中调用bar(3)

解决方法是使用一个包装器extern "C"函数调用适当的非C函数。这个函数可以从C中调用,你会得到想要的结果。

例如,如果你看一下链接器管理的标识符名称,你会看到编译器如何在链接时间和重载之间破坏标识符。如果您在C++中声明函数extern "C",则不会发生这种情况。

另一个原因是您没有C中的名称空间。C函数版本必须在全局名称空间级别可见。您无法在名称空间内隐藏C调用约定,因为它可以从所有C代码调用,或者您将违反C调用约定。

+0

这不是一个“原因”,它只是对问题的解释。 – Matt 2015-02-13 18:08:35