是否保证相同内容字符串文字的存储相同?

时间:2018-09-20 11:13:18

标签: c++ storage language-lawyer string-literals

下面的代码安全吗?编写与此类似的代码可能很诱人:

#include <map>

const std::map<const char*, int> m = {
    {"text1", 1},
    {"text2", 2}
};

int main () {
    volatile const auto a = m.at("text1");
    return 0;
}

该映射仅可用于字符串文字。

我认为这完全合法,并且似乎可以正常工作,但是我从来没有见过保证在两个不同地方使用的文字的指针是相同的。我无法使编译器为具有相同内容的文字生成两个单独的指针,所以我开始怀疑这个假设有多牢固。

我只对内容相同的文字是否可以具有不同的指针感兴趣。或更正式地讲,上面的代码可以吗?

我知道有一种方法可以确保代码能正常工作,并且我认为上述方法很危险,因为编译器可以决定为文字分配两个不同的存储,尤其是当它们放置在不同的翻译单元中时。我说的对吗?

4 个答案:

答案 0 :(得分:20)

具有完全相同内容的两个字符串文字是否是完全相同的对象,未指定,在我看来,最好不要依赖。引用标准:

  

[lex.string]

     

16计算字符串文字的结果是字符串文字对象   具有静态存储期限,从给定字符初始化为   以上指定。是否所有字符串文字都不同(即,   存储在非重叠对象中)以及是否连续   字符串文字的求值得出相同或不同的对象   未指定。

如果希望避免<div class="input-group"> <input type="text" name="" id="" placeholder="+235" class="prefix"> <input type="tel" name="" id="" class="uniqpart"> </div> 的开销,则可以编写一个简单的视图类型(或在C ++ 17中使用.input-group { width: 100%; display: flex; } input { outline: none; border: none; height: 40px; font-size: 1.5em; line-height: 40px; box-shadow: 0px 1px 8px 1px rgba(0,0,0,0.6) inset; } .prefix { width: 60px; border-radius: 30px 0 0 30px; padding: 10px 20px; } .uniqpart { border-radius: 0 30px 30px 0; padding: 10px 20px; margin-left: 10px; flex-grow: 5; } ),该视图类型是字符串文字上的引用类型。用它来进行智能比较,而不必依赖于文字标识。

答案 1 :(得分:18)

标准不保证内容相同的字符串文字的地址相同。实际上,[lex.string]/16说:

  

所有字符串文字是否都不同(即存储在不重叠的对象中),并且未确定对 string-literal 的连续求值是产生相同对象还是不同对象。

第二部分甚至说当第二次调用包含字符串文字的函数时,您可能不会获得相同的地址!尽管我从未见过编译器能够做到这一点。

因此,在重复字符串文字时使用相同的字符数组对象是可选的编译器优化。通过安装g ++和默认的编译器标志,我还发现我在同一翻译单元中获得两个相同字符串文字的相同地址。但是正如您所猜测的,如果相同的字符串文字内容以不同的翻译单位出现,我会得到不同的答案。


一个相关的有趣之处:不同的字符串文字也可以使用重叠数组。也就是说,给定

const char* abcdef = "abcdef";
const char* def = "def";
const char* def0gh = "def\0gh";

您可能会发现abcdef+3defdef0gh都是相同的指针。

此外,有关重用或重叠字符串文字对象的规则仅适用于直接与文字相关联的未命名数组对象,如果文字立即分解为指针或绑定到数组的引用,则使用此规则。文字也可以用于初始化命名数组,如

const char a1[] = "XYZ";
const char a2[] = "XYZ";
const char a3[] = "Z";

在这里,数组对象a1a2a3使用立即数初始化,但被认为与实际的立即数存储区分开(如果甚至存在此类存储区),并遵循普通的对象规则,因此这些数组的存储不会重叠。

答案 2 :(得分:5)

不,C ++标准不提供任何此类保证。

也就是说,如果代码位于同一翻译单元中,那么将很难找到反例。如果main()的翻译不同,那么反例可能会更容易产生。

如果地图位于其他动态链接库或共享对象中,则几乎可以肯定不是这种情况。

volatile限定词是红色鲱鱼。

答案 3 :(得分:3)

C ++标准不需要对字符串文字进行重复数据删除的实现。

当字符串文字驻留在另一个需要链接程序(ld或运行时链接程序(ld.so)的翻译单元或共享库中时,将进行字符串文字重复数据删除。他们没有。