我试图定义我可以在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定义?
答案 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
链接,因此在所有翻译单元中都是相同的。