2015-02-11 55 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

相關問題