在头文件中使用`const char thing [] =“foo”;`

时间:2014-09-22 17:54:50

标签: c++ dry one-definition-rule

我想创建一个常量全局字符数组,以便

  • 它可用于多个翻译单元。
  • 数组的长度是从用于初始化它的字符串文字中推导出来的。
  • 该字符串文字在我的源中只存在一次(如果可能的话,还存在目标文件)。
  • 所有翻译单元都有编译时间访问长度。
  • 多个翻译单元链接在一起时没有ODR违规。

理论上应该可以通过使用const char[]并将减速/定义放在头文件中,以强制数据/符号进入COMDAT部分,但我不知道是否符合标准(甚至任何编译器都支持。

P.S。假设使用的任何习语将用于跨越许多文件的数百到数千个常量。


编辑:我所知道的“最干净”的解决方案是:

template<bool> struct data_ {
  static const char kFoo[];
};

template<> const char data_<true>::kFoo[] = "bar\0other\0stuff\0";
typedef data_<true> data;


#include <stdio.h>

template<typename T, int N>
void Print(T(&var)[N]) { printf("%d %s\n", N, var); }

int main() { Print(data::kFoo); return 0; }

哪个还是比较难看。


OTOH如果我只是扔掉3b(保证相同的存储模块内联),那么这项工作:

const char kFoo[] = "bar\0other\0stuff\0";

因为默认情况下它有内部链接。一个好的链接器可以合并这些,但是在那时你不能说出地址/标识符相等之间的关系(即不要将它转换为指针并将其用作标识)。但这是一个警告,可能一直是良性的几乎

3 个答案:

答案 0 :(得分:2)

部首:

#define LITERAL "Hello, world"
extern char const literal[sizeof LITERAL];

一个源文件:

char const literal[] = LITERAL;

仍然无法保证任何特定的编译器/链接器只能生成字符串文字的一个副本(但它确保要求&literal[0]在所有单元中都相同)。

答案 1 :(得分:1)

从C ++ 17开始,您可以在标题中写入:

inline char const thing[] = "foo";

符合所有标准。

注意: inline变量具有外部链接,除非明确声明为static。关于const变量默认为内部链接的规则仅适用于非内联变量。

答案 2 :(得分:-3)

你不想要

const char * const LITERAL="foo";