如何比较 const char* 字符串?

How const char* strings are compared?

首先,考虑这个例子:

#include <iostream>
using namespace std;

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

我期望什么:因为“123”是一个 const char*,我希望比较这些字符串的地址 (like one of these answers said)。

... because != and == will only compare the base addresses of those strings. Not the contents of the strings themselves.

但输出仍然是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*是怎么比较的呢?

为什么这里的输出是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 的比较是如何实现的?

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

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

[lex.string.14] Evaluating a string-literal results in a string literal object with static storage duration, initialized from the given characters as specified above. Whether all string-literals are distinct (that is, are stored in nonoverlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified.

const char* 应该衰变成什么?数组会衰减,指针不会。

#include <iostream>
using namespace std;

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

returns1只是因为a恰好指向比b更高的地址,所以没有进行字典序比较。如果需要,只需使用 std::stringstd::string_view

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

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

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

来自不同 .cpp 文件的相同文字字符串也可能在最终链接的可执行文件中只产生一个字符串,而两个字符串最初是在不同的 [=11] 中编译的=] 完全相同,最终得到相同的实际指针值。

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

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

本次比较

"123" == "123"

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

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

至于这个节目

#include <iostream>
using namespace std;

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

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

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

I expect ADDRESSES (like one of these answers said) of these strings to be compared.

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

Or compiler managed to do some optimizations and allocate memory only for one string?

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

#include <iostream>
using namespace std;

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

更进一步:

事实上,为您进行了优化意味着您可以愉快地编写如下内容,即使在内存受限的嵌入式系统上,知道用完的程序 space 不会增加大小每次使用字符串文字时的字符串文字:

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);

另请参阅: