[英]extern “C” linkage inside C++ namespace?
namespace someNameSpace {
extern "C" void doSomething()
{
someOperations();
}
}
我想在 C++ 和 C 環境中運行doSomething()
。
如果我將someNameSpace
暴露給extern "C"
鏈接,它是否仍然封裝doSomething()
?
有沒有一種在 C++ 和 C 之間共享函數同時避免污染 C++ 端的全局命名空間的好方法?
編輯:因為此代碼主要用於 C++ 模式,而 C 鏈接僅供測試使用,我想這是一個更好的方法。
namespace someNameSpace {
#ifdef COMPILE_FOR_C_LINKAGE
extern "C"
#else
extern "C++"
#endif
{
void doSomething()
{
someOperations();
}
}
}
您的代碼有效,但您應該注意所有具有extern "C"
鏈接的函數共享相同的名稱空間,但這不要與“命名空間”的 C++ 概念混淆:您的函數實際上是someNameSpace::doSomething
,但是您不能在任何其他命名空間中使用任何其他具有非限定名稱doSomething
extern "C"
函數。
見 7.5/6:
最多一個具有特定名稱的函數可以具有 C 語言鏈接。 出現在不同命名空間作用域中的具有相同函數名稱(忽略限定它的命名空間名稱)的具有 C 語言鏈接的函數的兩個聲明引用同一個函數。 出現在不同命名空間范圍內的具有相同名稱的 C 語言鏈接變量的兩個聲明(忽略限定它的命名空間名稱)引用同一個變量。 具有 C 語言鏈接的實體不得與全局范圍內的變量同名聲明,除非兩個聲明表示同一實體; 如果聲明出現在不同的翻譯單元中,則不需要診斷。 具有 C 語言鏈接的變量不得與具有 C 語言鏈接的函數使用相同的名稱(忽略限定各自名稱的命名空間名稱); 如果聲明出現在不同的翻譯單元中,則不需要診斷。 [注意:在程序中只能出現一個具有給定名稱的具有C語言鏈接的實體的定義(見3.2); 這意味着不能在多個命名空間范圍內定義這樣的實體。 —尾注]
您公司或項目的全球風格仲裁者應該能夠就適合您的代碼庫的命名策略向您提供建議。
只是一段代碼來說明 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;
}
在 C++ ABI 中,命名空間必須被破壞。 所以這:
namespace foo
{
void bar(int){}
}
或多或少被翻譯成這樣的符號:
foo::bar(int)
當你強制編譯器使用 C ABI 時,類似的符號
namespace foo
{
extern "C" void bazz(int){}
}
編譯后如下所示:
bazz
你可以看到godbolt的區別: 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 編譯器只發出簡單的編譯錯誤:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.