2015-11-06 82 views
1

我想定義可以在cpp文件中使用的常量字符串,這樣數據和指針都不能被修改。鏈接器抱怨如下:外部const指針的const正確性

main.obj:錯誤LNK2001:無法解析的外部符號 「字符常量* 常量g_someString」

示例代碼:

//constants.h 
extern const char * const g_someString; 

//constants.cpp 
const char * const g_someString = "Hello"; 

// main.cpp 
int main() 
{ 
    strcmp(g_someString, "Hello"); 
} 

這不當const char * const被const char *替換時會發生。編譯器(MSVC 2015)是否優化了constants.cpp中的g_someString定義?

+0

在_constants.cpp_ – Karthik

+0

中的定義確保'constants.cpp'包含'constants.h'(並且沒有循環依賴關係) –

+0

'void main'的定義之前,鏈接器錯誤消失了_extern_聲明在C++中是非法的,即使你的編譯器提供了一個不合規的擴展名,編寫依賴於這些擴展名的代碼也是不好的 –

回答

4

之前

const char * const g_someString = "Hello"; 

你需要將其聲明爲extern(例如通過包括頭部),因爲const命名空間層次變量的缺省內部鏈接。


也就是說,你可以在標題中定義字符串。單獨的編譯讓您可以修改字符串而不會重建大量文件,但除此之外,恕我直言,這是過早的優化。


爲了使字符串定義在頭正式安全的inline功能,如果這是需要的,你需要的字符串(或至少是指針)有extern聯動。一種方法是在一個定義規則中利用特殊的模板豁免。例如。像這樣:

// Perhaps best generated by some code generation facility: 
template< class Dummy > 
struct Strings_ 
{ 
    static char const* const some_string; 
    static char const* const some_other_string; 
}; 

template< class Dummy > 
char const* const Strings_<Dummy>::some_string = "Blah!"; 

template< class Dummy > 
char const* const Strings_<Dummy>::some_string = "Oh, well."; 

using Strings = Strings_<void>; 

然後使用像

inline void foo() { cout << Strings::some_string << endl; } 

這裏Strings::some_string指針會在所有的翻譯單位相同。

另一種方法是定義inline函數中的字符串。然後你可以使用例如枚舉來命名它們。

enum String_id { some_string, some_other_string }; 

inline 
auto strings(String_id const id) 
    -> char const* 
{ 
    switch(id) 
    { 
    case some_string:   return "Blah!"; 
    case some_other_string: return "Oh, well."; 
    } 
    assert(false); // Should never get here. 
} 

與使用像

inline void foo() { cout << strings(some_string) << endl; } 

inline功能有extern聯動,因此它在所有的翻譯單位相同。

+0

單獨編譯也可以幫助編譯器執行字符串池。 –

+0

在頭文件中定義字符串的一個陷阱是,如果一個'inline'函數使用這樣的字符串,它會導致未定義的行爲。 (並不是說你不應該在頭文件中定義字符串,只是必須知道這個陷阱) –

+0

@ M.M:謝謝,我沒有想到(儘管我一度意識到這一點)。我只想過是否提及如何在外部鏈接的標題中做到這一點,但決定只會使答案複雜化。現在我不太確定,嗯。無論如何,要定義標題中的字符串和外部鏈接,可以使用舊的模板常量技巧。 –