2010-05-09 58 views
6

我有一個使用C bison解析器的C++項目。的C解析器使用函數指針的結構來調用創建正確的AST節點的功能時,野牛減少製作:現在在未命名的命名空間中定義的C回調函數?

typedef void Node; 
struct Actions { 
    Node *(*newIntLit)(int val); 
    Node *(*newAsgnExpr)(Node *left, Node *right); 
    /* ... */ 
}; 

,在該項目的C++部分,我填這些指針

class AstNode { 
    /* ... */ 
}; 
class IntLit : public AstNode { 
    /* ... */ 
}; 

extern "C" { 
    Node *newIntLit(int val) { 
    return (Node*)new IntLit(val); 
    } 

    /* ... */ 
} 

Actions createActions() { 
    Actions a; 
    a.newIntLit = &newIntLit; 
    /* ... */ 
    return a; 
} 

現在我把它們放入extern "C"的唯一原因是因爲我希望它們有C調用約定。但最好的是,我希望他們的名字仍然會被打亂。它們絕不會在C代碼中被稱爲副本名稱,所以名稱重組不是問題。讓它們被修改會避免名稱衝突,因爲一些動作被調用,如error,並且C++回調函數具有類似下面的醜陋名稱,以避免與其他模塊發生名稱衝突。

extern "C" { 
    void uglyNameError(char const *str) { 
    /* ... */ 
    } 

    /* ... */ 
} 

a.error = &uglyNameError; 

我想知道是否可以通過僅僅給函數C型連鎖

extern "C" void fty(char const *str); 
namespace { 
    fty error; /* Declared! But i can i define it with that type!? */ 
} 

任何想法可能嗎?我正在尋找Standard-C++解決方案。

+0

難道你不能將Bison輸出編譯爲C++代碼,從而完全避免了這個問題嗎? – 2010-05-09 13:16:45

+0

@我的同事@Konrad說,野牛C++模式不好處理,所以我們用純C做這個部分並將它抽象出來,所以和掃描器一起構成一個純C庫。 – 2010-05-09 13:34:11

回答

3

我不明白這個問題。 extern關鍵字不會影響調用約定,只是提供給鏈接器的名稱。用C++編寫的函數不是實例方法,它仍然是__cdecl,有或沒有extern「C」。此外,只要將createActions()保留在同一個源代碼文件中,這些函數就不需要外部鏈接。你可以聲明它們是靜態的,或者把它們放在一個未命名的名字空間中以避免衝突。

+2

啊,我可以做'靜態'。好主意,爲什麼我沒想到:)我只想到了未命名的命名空間,但是這對它們的連接沒有任何作用,並且不會阻止'extern「C」'函數的衝突。但'靜態'實際上可以工作!對於答案的其餘部分:如果實現希望這樣做,則可以調用約定。我想不依賴於任何特定的實現,所以我讓它們成爲'extern'C''。 – 2010-05-09 12:53:18