簡體   English   中英

僅在函數聲明中需要extern“ C”嗎?

[英]Is extern “C” only required on the function declaration?

我寫了一個C ++函數,需要從C程序中調用。 為了使其可以從C調用,我在函數聲明中指定了extern "C" 然后,我編譯了C ++代碼,但是編譯器(Dignus Systems / C ++)為該函數生成了錯誤的名稱 因此,它顯然不尊重extern "C"

為了解決這個問題,我在函數定義中添加了extern "C" 此后,編譯器生成了可從C調用的函數名稱。

從技術上講,僅在函數聲明中指定extern "C"即可。 這是正確的嗎? C ++ FAQ中有一個很好的例子。)是否還要在函數定義中指定它?

這是一個示例來證明這一點:

/* ---------- */
/* "foo.h"    */
/* ---------- */

#ifdef __cplusplus
extern "C" {
#endif

/* Function declaration */
void foo(int);

#ifdef __cplusplus
}
#endif

/* ---------- */
/* "foo.cpp"  */
/* ---------- */

#include "foo.h"

/* Function definition */
extern "C"               // <---- Is this needed?
void foo(int i) {
  // do something...
}

我的問題可能是錯誤編碼的結果,或者我發現了編譯器錯誤。 無論如何,我都想咨詢stackoverflow以確保我知道哪一種在技術上是“正確的”方法。

只要定義具有聲明並且在定義的編譯中已經看到,在函數定義上就不需要' extern "C" '。 該標准特別聲明(7.5 / 5鏈接規范):

在看到顯式鏈接規范之后,可以在沒有鏈接規范的情況下聲明函數; 先前的聲明中明確指定的鏈接不受此函數聲明的影響。

但是,我通常也會在定義上加上' extern "C" ',因為它實際上是具有extern“ C”鏈接的函數。 很多人討厭不必要的冗余內容(例如將virtual放在方法重寫上),但是我不是其中之一。

編輯:
好像我誤解了這個問題。 無論如何,我嘗試過:


// foo.cpp
/* Function definition */

#include "foo.h"

void foo(int i) {
 //do stuff
}
void test(int i)
{
// do stuff
}

// foo.h
#ifdef __cplusplus
extern "C" {
#endif

/* Function declaration */
void foo(int);

#ifdef __cplusplus
}
#endif

void test(int);

使用命令nm查看已編譯文件中的符號:


linuxuser$ nm foo.o
00000006 T _Z4testi
         U __gxx_personality_v0
00000000 T foo

顯然,這表明聲明為extern“ C”的函數的名稱沒有被篡改,並且定義時不需要extern“ C”關鍵字。
如果它要求每個不帶外部“ C”編寫的C庫代碼在C ++程序中將無法使用。

不需要在定義周圍加上extern "C" 您可以將其放在聲明周圍。 您的示例中有一個音符...

#ifdef __cplusplus
extern "C" {
#endif

/* Function declaration */
void foo(int);

#ifdef __cplusplus
}
#endif

您的代碼正在尋找預處理器宏“ __cplusplus ”。

雖然通常實現,但可能會或可能不會定義,具體取決於您的編譯器。 在您的示例中,您還在聲明周圍使用了extern "C" ,但是您沒有在檢查“ __cplusplus ”宏,這就是為什么我懷疑它一旦執行就可以工作的原因。

請參閱下面的注釋-標准C ++要求__cplusplus宏由預處理器定義。

剛遇到這種情況。

在我的一個c文件中聲明了以下內容:

void unused_isr(void) {}
void ADC_IRQHandler(void)     __attribute__ ((weak, alias("unused_isr"))); 

接下來,在我定義的cpp文件中的某個位置:

void ADC_IRQHandler(void) {                                                                                  
    ...
}

我忘了將前向聲明更改為:

void ADC_IRQHandler(void);

我花了一段時間才弄清楚我對AD轉換所做的一切正確,但是我未能在定義中添加“ extern C”!

extern "C" void ADC_IRQHandler(void) {                                                                                  
    ...
}

僅花費我的兩分錢,為什么在某些情況下也有習慣將其添加到定義中可能有用。

我認為這里需要澄清,因為我有一個類似的問題,花了我一段時間才弄清楚了,只有布魯克斯·摩西(Brooks Moses)正確地指出了這一點,我認為需要更清楚地說明。 。

總而言之,標頭可能會讓您失望,編譯器看到的只是cpp文件,如果標頭不包含在extern“ C”中,則返回到您的cpp中(我通常會看到),那么extern“ C”將需要位於cpp文件中的某個位置(無論是在定義中還是在其他聲明中),因此CXX編譯器可以知道使用C鏈接進行編譯,因此,編譯器不關心標題,而僅關心鏈接器。

它應該同時存在。 編譯器在編譯調用站點(可能只能看到一個聲明)時需要知道使用C符號名稱和調用約定,並且編譯器還需要在生成C站點時知道生成C符號名稱並使用C調用約定。函數定義本身(可能看不到任何其他聲明)。

現在,如果您有一個在定義所在的翻譯單元中可以看到的extern-C聲明,則可以擺脫定義中的extern-C,但是我不確定。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM