对于extern const指针的const正确性

时间:2015-11-06 02:15:49

标签: c++ pointers

我试图定义我可以在cpp文件中使用的常量字符串,这样既不能修改数据,也不能修改指针。链接器抱怨如下:

  

main.obj:错误LNK2001:未解析的外部符号" char const *   const 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定义?

1 个答案:

答案 0 :(得分:4)

const char * const g_someString = "Hello";

您需要将其声明为extern(例如,通过包含标头),因为const命名空间级别变量默认具有内部链接。

也就是说,你可以在标题中定义字符串。单独的编译为您提供了修改字符串而不会导致重建大量文件的能力,但除此之外,恕我直言,这是不成熟的优化。

要使inline函数的头文件正式安全的字符串定义,如果需要,您需要字符串(或至少指针)具有extern链接。一种方法是在One Definition Rule中利用模板的特殊豁免。例如。像这样:

// 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链接,因此在所有翻译单元中都是相同的。