不同翻译单元中字符串文字的内存地址是否相同?

Kar*_*yan 3 c++ memory string-literals

假设我们有以下代码片段。

#include <iostream>

int main(){
    const char* p1="hello";
    const char* p2="hello";
    std::cout<<p1==p2;
}
Run Code Online (Sandbox Code Playgroud)

输出

1
Run Code Online (Sandbox Code Playgroud)

正如我们所知,p1 和 p2 指向相同的内存地址(如果我错了,请纠正我)。

现在,假设我们在不同的翻译单元中定义了这些指针:

1
Run Code Online (Sandbox Code Playgroud)

我的问题是,指向pA和的内存地址是否pB仍然相同,如果是,在哪些情况下它们可能不同(例如使用关键字等等)?

Adr*_*ica 5

正如评论中提到的,C++ 标准不强制是否应该合并多重定义的相同字符串文字:

5.13.5 字符串文字 [lex.string]


16    对字符串字面量求值会产生一个具有静态存储持续时间的字符串字面量对象,从上面指定的给定字符初始化。是否所有字符串文字都是不同的(即存储在非重叠对象中)以及字符串文字的连续计算是否产生相同或不同的对象是未指定的。

通常,编译器(或链接器)提供命令行开关来决定是否合并相同的字符串。例如,MSVC 编译器具有“启用字符串池”选项 -/GF合并或/GF-保持它们分开。

使用以下代码单元:

#include <iostream>
extern void other();

int main()
{
    const char* inmain = "hello";
    std::cout << (void*)(inmain) << std::endl;
    other();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

和(在一个单独的源文件中):

#include <iostream>

void other()
{
    const char* inother = "hello";
    std::cout << (void*)(inother) << std::endl;

}
Run Code Online (Sandbox Code Playgroud)

使用/GFswitch 生成如下输出(字符串具有相同的地址):

00007FF778952230
00007FF778952230
Run Code Online (Sandbox Code Playgroud)

但是,使用/GF-产品:

00007FF7D5662238
00007FF7D5662230
Run Code Online (Sandbox Code Playgroud)

事实上,即使是您的第一个代码片段(稍作修改,如下所示),其中两个文字都在同一个翻译单元(甚至在同一范围内)在使用选项构建时会生成两个不同的对象/GF-

#include <iostream>
#include <ios>

int main()
{
    const char* p1 = "hello";
    const char* p2 = "hello";
    std::cout << std::boolalpha << (p1 == p2) << std::endl;
    // Output: "false" using /GF- or "true" using /GF
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 对于 GCC,我发现`-fno-merge-constants` 等同于 MSVC `/GF-` 开关的模糊参考。但是,我找不到权威来源来证实这一点。 (2认同)