namespace someNameSpace {
extern "C" void doSomething()
{
someOperations();
}
}
我想在C ++和C环境中运行doSomething()
。
如果我将someNameSpace
公开给doSomething()
链接,extern "C"
是否仍会封装namespace someNameSpace {
#ifdef COMPILE_FOR_C_LINKAGE
extern "C"
#else
extern "C++"
#endif
{
void doSomething()
{
someOperations();
}
}
}
?
有没有一种很好的方法在C ++和C之间共享函数,同时避免在C ++端污染全局命名空间?
编辑:因为此代码主要用于C ++模式,而C链接仅供测试使用,我想这是一种更好的方法。
{{1}}
答案 0 :(得分:15)
您的代码有效,但您应该注意所有具有extern "C"
链接的函数共享相同的名称空间,但不要与“命名空间”的C ++概念混淆:您的函数真的是{ {1}},但您不能在任何其他名称空间中使用具有非限定名称someNameSpace::doSomething
的任何其他extern "C"
函数。
见7.5 / 6:
最多一个具有特定名称的函数可以具有C语言链接。函数的两个声明 与C语言链接具有相同的函数名称(忽略限定它的命名空间名称) 出现在不同的命名空间范围内引用相同的函数。带C的变量的两个声明 具有相同名称的语言链接(忽略限定它的命名空间名称)出现在不同的语言链接中 命名空间范围指的是同一个变量。具有C语言链接的实体不得声明 与全局范围内的变量同名,除非两个声明都表示同一个实体;没有诊断 如果声明出现在不同的翻译单元中,则需要。具有C语言链接的变量不得 声明与具有C语言链接的函数同名(忽略名称空间名称) 限定相应的名称);如果声明出现在不同的翻译中,则无需诊断 单位。 [注意:对于具有C语言链接的给定名称的实体,只能出现一个定义 该计划(见3.2);这意味着不能在多个名称空间中定义这样的实体 范围。 - 结束记录]
贵公司或项目的全球风格仲裁者应该能够为您的代码库提供合适的命名政策建议。
答案 1 :(得分:6)
只是一段代码来说明Kerrek SB回答中陈述的行为
#include <iostream>
namespace C{
void Hello(){
std::cout<<"Hello"<<std::endl;
}
extern "C" void HelloThere(){
std::cout<<"Hello There from extern \"C\""<<std::endl;
}
}
extern "C" void HelloThere();
int main() {
C::Hello();
C::HelloThere(); //Compiles
//Hello(); <--- does not compile
HelloThere(); //Also compiles and prints the same as C::HelloThere() !!!
return 0;
}
答案 2 :(得分:0)
在C ++ ABI中,必须修改名称空间。所以这个:
namespace foo
{
void bar(int){}
}
或多或少被翻译成这样的符号:
foo::bar(int)
当您强制编译器使用C ABI时,类似的符号
namespace foo
{
extern "C" void bazz(int){}
}
编译后如下:
bazz
您可以看到不同之处: https://godbolt.org/z/BmVpSQ
在C ABI中,该函数没有名称空间或参数列表,因此在整个代码中只能有1个这样的符号。定义两次:
namespace foo
{
extern "C" void bazz(int){}
}
namespace foo2
{
extern "C" void bazz(int){}
}
int main()
{
foo2::bazz(5);
return 0;
}
...是非法的。 令我惊讶的是,gcc不会发出编译/链接错误,但是会出现运行时错误出于某种原因,gcc编译器会发出非常奇怪的错误:
https://wandbox.org/permlink/BiN0auna9klBg5GE
在这种情况下,clang编译器发出的只是发出简单的编译错误: