2012-12-11 102 views
1

我在函數中使用前向聲明時遇到問題。通常在全局範圍內,我們可以使用使用extern關鍵字聲明的未定義變量的地址。看看這個簡單的例子。函數中的前向聲明

typedef struct Id { 
    int a; 
} xIdRec; 

typedef xIdRec* IdN; 

typedef struct ChId{ 
    int a; 
    IdN* b; 
} ChIdRec; 

extern ChIdRec Evn; 
IdN Arr[] = {(IdN)&Evn}; 
ChIdRec Evn = {8, Arr};  

但我怎麼能在函數定義使用此代碼?我們可以嘗試像這樣使用它。

void F(){ 
    typedef struct Id { 
     int a; 
    } xIdRec; 

    typedef xIdRec* IdN; 

    typedef struct ChId{ 
     int a; 
     IdN* b; 
    } ChIdRec; 

    extern ChIdRec Evn; 
    IdN Arr[] = {(IdN)&Evn}; 
    ChIdRec Evn = {8, Arr}; 
} 

但是,現在我們有一個錯誤 - error C2086: 'ChIdRec Evn' : redefinition。 我們可以刪除第一個聲明Evn,但是我們會有另一個錯誤 - error C2065: 'Evn' : undeclared identifier

我該如何解決這個問題?

+2

嗯..移動它的功能以外? –

+0

'struct ChIdRec'是一個局部結構,它如何在函數'F()'之外實例化? – mark

+0

爲什麼你在本地再次聲明'extern ChIdRec Evn'? 'extern foo bar'應該只出現一次,即在實現'foo bar'的模塊(如果有的話)的頭文件中。 – alk

回答

1

不要重複函數內部類型的定義。特別是typedef表示這是一個新的標識符,即使它具有與全局標識符相同的名稱和含義。

+0

我想你認爲這兩個代碼塊應該一個接一個地編譯? – Yakk

+0

我認爲OP的錯誤顯示了這正是發生的事情。 – Useless

0

extern表示該變量在另一個代碼單元中被定義爲由鏈接器解析。如果結構是在本地函數中定義的,那麼我也看不出你如何期望它是extern

問題是你有一個外部變量,然後你試圖聲明與本地相同的變量。編譯器正在說:「定下你的想法,是外部的還是本地的?」。

看起來,您的轉發聲明的唯一原因是您可以在結構上使用{ }初始化語法。最好由會員分配會員比使用黑客更好。

如果你必須那麼你可以使用void *,但這是灑了陷阱爲粗心。

0

extern ChIdRec Evn;不會做你認爲它在函數內部放時。

extern變量是一個全局變量。即使你在函數中聲明它。這讓你可以說你正在使用一個extern全局變量通過一個函數體,在你訪問它的地方的右邊。但它確實意味着你不能「轉發聲明」一個局部變量。

現在,理論上你可以在一個地方創建你的struct而不用構造它,做一些更多的工作,然後在C++ 11中使用統一的初始化語法就地創建new

即:

ChIdRec Evn; 
IdN Arr[] = {(IdN)&Evn}; 
new(&Evn)ChIdRec{8, Arr}; 

或類似的東西。 (注意使用放置new的,我沒有創造的自由存儲區(也稱爲堆)內存還要指出的是ChIdRec雙建設是危險的,如果它不是POD - 如果ChIdRec含有std::string,我希望以上泄漏或崩潰,比如

一個稍微可笑,但正確的方法:

unsigned char EvnBuff[sizeof(ChIdRec)]; 
IdN Arr[] = {reinterpret_cast<IdN>(&EvnBuff[0])}; 
new(&EvnBuff[0])ChIdRec{8, Arr}; 
ChIdRec& Evn = *reinterpret_cast<ChIdRec*>(&EvnBuff[0]); 
// ... code goes here 
Evn->~ChIdRec(); // before leaving body of function, iff ChIdRec::~ChIdRec exists 

可能在花哨的東西打扮,使其異常安全和方便些。基本上,延遲施工抽象會使這個邊界更不可笑。