为什么(仅)某些编译器对相同的字符串文字使用相同的地址?

Eug*_*sov 88 c++ string-literals string-interning language-lawyer

https://godbolt.org/z/cyBiWY

我可以'some'在MSVC生成的汇编代码中看到两个文字,但只有一个有clang和gcc.这导致完全不同的代码执行结果.

static const char *A = "some";
static const char *B = "some";

void f() {
    if (A == B) {
        throw "Hello, string merging!";
    }
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释这些编译输出之间的差异和相似之处吗?为什么即使没有请求优化,clang/gcc也会优化某些内容?这是某种未定义的行为吗?

我还注意到,如果我将声明更改为下面显示的声明,则clang/gcc/msvc根本不会"some"在汇编代码中留下任何声明.为什么行为不同?

static const char A[] = "some";
static const char B[] = "some";
Run Code Online (Sandbox Code Playgroud)

son*_*yao 106

这不是未定义的行为,而是未指定的行为.对于字符串文字,

允许编译器(但不是必需的)将存储组合为相等或重叠的字符串文字.这意味着当通过指针进行比较时,相同的字符串文字可能会或可能不会比较相等.

这意味着结果A == B可能是,true或者false你不应该依赖.

从标准,[lex.string]/16:

是否所有字符串文字都是不同的(即,存储在非重叠对象中)以及是否对字符串文字的连续评估产生相同或不同的对象是未指定的.


tob*_*i_s 35

其他答案解释了为什么你不能指望指针地址不同.然而,您可以轻松地以保证A并且B不比较相等的方式重写它:

static const char A[] = "same";
static const char B[] = "same";// but different

void f() {
    if (A == B) {
        throw "Hello, string merging!";
    }
}
Run Code Online (Sandbox Code Playgroud)

不同的是AB现在字符数组.这意味着它们不是指针,它们的地址必须是不同的,就像两个整数变量必须的那样.C++混淆了这一点,因为它使得指针和数组看起来可以互换(operator*并且operator[]看起来表现相同),但它们确实不同.例如,const char *A = "foo"; A++;完全合法的东西,但const char A[] = "bar"; A++;不是.

考虑差异的一种方法是char A[] = "..."说"给我一块记忆并用...随后的字符填充\0",然后char *A= "..."说"给我一个地址,我可以找到...后面跟着的字符\0".

  • 如果你能解释*为什么*它不同,这将是一个更好的答案. (8认同)

Bat*_*eba 22

无论编译器选择使用相同的字符串位置A,并B达到实现.在形式上,您可以说您的代码行为未指定.

两种选择都正确地实现了C++标准.


归档时间:

查看次数:

6562 次

最近记录:

6 年,10 月 前