确保字符指针始终指向相同的字符串文字

Ensure that char pointers always point to the same string literal

本文关键字:字符串 文字 字符 指针 确保      更新时间:2023-10-16

给定代码

// somewhere in the program
const char* p1 = "Hello World";
// somewhere else in the program
const char* p2 = "Hello World";

有没有办法确保p1 == p2在整个程序/库中始终得到满足?我的意思是p1p2总是引用相同的字符串文字。

背后的原因

我试图实现的是使用const char*作为std::map<const char*, something>的密钥。我有一个宏

#define nameof(id) #id

它模仿了C#中nameof关键字的行为(我知道这已经有缺陷了(,我想用它来访问类似注册表的结构,例如

void foo()
{
auto x = getMapping(nameof(foo));
}
// different place in code
void registerFoo(something x)
{
setMapping("foo", x);
}

正如Barry在他们的回答中所表明的那样,你想要的行为并不能得到保证。您将不得不支付字符串比较的费用,但您至少可以通过使用std::string_view来避免任何内存分配或编写比较器。std::string_view是字符串的轻量级视图,它包含指向字符串数据和字符串大小的指针,并且它有一个内置的operator <,可以进行字典比较。那会把你的地图改成

std::map<std::string_view, something>

没有这样的要求。[lex.string]/15:

是否所有字符串文字都是不同的(即存储在不重叠的对象中(,以及字符串文字的连续求值是产生相同的对象还是产生不同的对象,都未指定。

你能做的最好的事情是assert(),或者只是避免重复你自己,把事情放在一个函数中:

char const* my_literal() { return "Hello World"; }
char const* p1 = my_literal();
char const* p2 = my_literal();

相同的文字字符串不能保证是相同的,但是当您使用MACRO创建字符串时,您可以将其更改为返回相同的字符串。

gcc/clang有一个扩展,允许从文字字符串构建UDL:

template<typename Char, Char... Cs>
struct CsHelper
{
static constexpr const Char s[] = {Cs..., 0}; // The unique address
};
// That template uses the extension
template<typename Char, Char... Cs>
constexpr auto operator"" _cs() -> const Char (&)[1 + sizeof...(Cs)] {
return CsHelper<Char, Cs...>::s;
}

然后

#define nameof(id) #id ## _cs

请参阅我在compiletime的String interning中的回答,如果您不能使用扩展,则可以使用MAKE_STRING宏进行分析(对于可接受的字符串长度,确实更详细,并且是硬编码的限制(。

不要求具有相同文本的两个字符串文字是同一对象。因此,”Hello world”的两次提及可能指代也可能不指代存储器中的单个字符串。这意味着

const char* p1 = "Hello World";
const char* p2 = "Hello World";

并不一定使p1等于p2。要做到这一点,你必须将其中一个设置为与另一个相等:

const char* p2 = p1;

但其中任何一个指针都可以修改,而另一个指针不会跟踪这种变化。为了确保不能进行这样的更改,请将指针设为常量:

const char* const p1 = "Hello World";
const char* const p2 = p1;

或者,如果p1需要修改,则将p2作为参考:

const char* p1 = "Hello World";
const char*& p2 = p1;

现在p2将指向上的任何p1

我不知道它是否有帮助,但在Visual Studio中有一个名为"的C++选项;启用字符串池";。

/GF(消除重复字符串(

使编译器能够在程序图像和执行期间的存储器中。这是一个称为字符串池的优化,可以创建更小的程序。