3

首先,考虑这个例子:

#include <iostream>
using namespace std;

int main()
{
    cout << ("123" == "123");
}

我期望什么:由于 "123" 是 a const char*,我希望这些字符串的 ADDRESSES (就像其中一个答案所说的那样)进行比较。

...因为!=并且==只会比较这些字符串的基地址。不是字符串本身的内容。

但输出仍然是1. 好吧,我们实际上不知道如何比较两个纯右值对象的地址(或者至少我不明白它是如何完成的)。所以让我们将这些字符串声明为变量,看看会发生什么:

#include <iostream>
using namespace std;

int main()
{
    const char* a = "1230";
    const char* b = "1230";
    cout << (a == b);
}

输出仍然是1. 所以const char*弦不会衰减?或者编译器设法进行一些优化并只为一个字符串分配内存?好的,让我们尽量避免它们:

#include <iostream>
using namespace std;

int main()
{
    const char* a = "1230";
    const char* b = "1231";
    b = "1230";
    cout << (a == b);
}

结果还是一样。这让我觉得const char*真的不会腐烂。但这并没有让我的生活变得更简单。那么const char*s 是如何比较的呢?

为什么这里的输出是1

#include <iostream>
using namespace std;

int main()
{
    const char* a = "1230";
    const char* b = "1231";
    cout << (a > b);
}

a小于b,就字典比较而言,但这里a更大。那么如何const char*实现 s 的比较呢?

4

4 回答 4

5

是的,链接的答案是正确的。operator==for 指针只比较地址,而不是它们的内容。

此外,编译器可以免费但不是必需的去重复字符串文字,因此所有出现的字符串文字都是相同的对象,具有相同的地址。这就是你观察到的,重新分配b = "1230";不会阻止它。

[lex.string.14]评估字符串文字会产生一个具有静态存储持续时间的字符串文字对象,从上面指定的给定字符初始化。是否所有字符串文字都是不同的(即,存储在不重叠的对象中)以及字符串文字的连续评估是否产生相同或不同的对象是未指定的。

应该const char*腐烂到什么程度?数组衰减,指针不会。

#include <iostream>
using namespace std;

int main()
{
    const char* a = "1230";
    const char* b = "1231";
    cout << (a > b);
}

返回1只是因为a碰巧指向比 更高的地址b,所以没有进行字典比较。只需使用std::stringstd::string_view如果您需要。

于 2021-11-21T12:51:25.227 回答
4

C++ 标准完全未指定文字字符串的存储细节(除了它们的生命周期),完全由编译器自行决定。例如:

const char *a="ABCDEFG";
const char *b="DEFG";

智能编译器完全有可能只生成一个字符串,并将第二个指针设置为指向字符串的中间。

来自不同文件的相同文字字符串也可能.cpp在最终的链接可执行文件中仅生成一个字符串,并且两个字符串最初.cpp完全不同地编译,最终具有相同的实际指针值。

同样,指针比较也是为 C++ 标准中未明确指定的所有其他情况定义的实现。指针比较具有定义的行为,主要用于指向同一数组或向量的成员的指针,并且通常完全未指定其他方式。在 C++ 标准中,有一些方法可以实现指针的总顺序,但这与这里无关。

总结一下:否则,您不能期望任何指针值有任何特定行为或特定含义。

于 2021-11-21T12:52:33.913 回答
2

在这个比较中

"123" == "123"

具有该类型的字符串文字const char[4]被隐式转换为指向其第一个元素的指针,并比较这些指针。

结果取决于编译器选项,这些选项指定相同的字符串文字是存储为一个字符串文字还是单独的字符串文字。

至于这个节目

#include <iostream>
using namespace std;

int main()
{
    const char* a = "1230";
    const char* b = "1231";
    cout << (a > b);
}

那么您不能将运算符 > 与不指向同一数组元素的指针一起使用。这样的比较是不确定的。

比较的结果取决于编译器将字符串文字放在字符串文字池中的顺序。

于 2021-11-21T12:52:39.007 回答
2

我希望对这些字符串的 ADDRESSES (就像其中一个答案所说的那样)进行比较。

正确,这就是 C 和 C++ 中发生的情况。在 C 和 C++ 中比较 C 字符串(字符数组)或字符串文字时,编译器仅比较它们的地址。

或者编译器设法进行一些优化并只为一个字符串分配内存?

是的!恰恰。编译器会看到"1230"两次,并且可能(在您/我们的情况下,确实如此,这就是我们看到这种行为的原因)只是在下面的代码中为它们两个在相同的确切内存位置使用相同的确切字符串。因此,它们具有相同的地址。这是 C 和 C++ 编译器可能为您做的一个很好的优化。

#include <iostream>
using namespace std;

int main()
{
    const char* a = "1230";
    const char* b = "1230";
    cout << (a == b);
}

更进一步:

为您进行优化这一事实意味着您可以愉快地编写如下内容,即使在内存受限的嵌入式系统上,也知道每次使用字符串字面量:

printf("some very long string\n");
printf("some very long string\n");
printf("some very long string\n");
printf("some very long string\n");

"some very long string"只在内存中存储一​​次。

话虽如此,如果您对该字符串进行了单个字符更改,编译器可能会选择使其成为内存中的新字符串,因此在上述情况下,您最好还是这样做:

constexpr char MY_MESSAGE[] = "some very long string\n";
// OR:
// #define MY_MESSAGE "some very long string\n"

printf(MY_MESSAGE);
printf(MY_MESSAGE);
printf(MY_MESSAGE);
printf(MY_MESSAGE);

也可以看看:

  1. 为什么(仅)某些编译器对相同的字符串文字使用相同的地址?
于 2021-11-21T12:53:41.943 回答