c++ - C++ 编译器如何合并相同的字符串文字

标签 c++ visual-c++ compiler-construction linker

编译器 (MS Visual C++ 2010) 如何在不同的 cpp 源文件中组合相同的字符串文字?例如,如果我分别在 src1.cpp 和 src2.cpp 中有字符串文字“hello world\n”。编译后的 exe 文件可能在常量/只读部分中只有 1 个“hello world”字符串文字。这个任务是由链接器完成的吗?

我希望实现的是,我得到了一些用汇编语言编写的模块,供 C++ 模块使用。这些汇编模块包含许多长字符串文字定义。我知道字符串文字与 C++ 源代码中的其他一些字符串文字相同。如果我将我的程序集生成的 obj 代码与编译器生成的 obj 代码链接起来,链接器是否会合并这些字符串文字以删除冗余字符串,就像所有模块都在 C++ 中一样?

最佳答案

(注意以下仅适用于 MSVC)

我的第一个答案具有误导性,因为我认为文字合并是链接器完成的魔术(因此只有链接器需要 /GF 标志)。

但是,这是一个错误。事实证明,链接器在合并字符串字面量方面几乎没有什么特别的参与——当 /GF 选项提供给编译器时,它会将字符串字面量放在目标文件的“COMDAT”部分中具有基于字符串文字内容的对象名称。所以 compile 步骤需要 /GF 标志,而不是链接步骤。

当您使用 /GF 选项时,编译器会将目标文件中的每个字符串文字作为 COMDAT 对象放在单独的部分中。链接器将折叠具有相同名称的各种 COMDAT 对象(我不确定 COMDAT 的语义,或者如果具有相同名称的对象具有不同的数据,链接器可能会做什么)。所以一个C文件包含

char* another_string = "this is a string";

在目标文件中会有如下内容:

SECTION HEADER #3
  .rdata name
       0 physical address
       0 virtual address
      11 size of raw data
     147 file pointer to raw data (00000147 to 00000157)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40301040 flags
         Initialized Data
         COMDAT; sym= "`string'" (??_C@_0BB@LFDAHJNG@this?5is?5a?5string?$AA@)
         4 byte align
         Read Only

RAW DATA #3
  00000000: 74 68 69 73 20 69 73 20 61 20 73 74 72 69 6E 67  this is a string
  00000010: 00      

使用重定位表将 another_string1 变量名连接到文字数据。

请注意,字符串文字对象的名称显然是基于文字字符串的内容,但带有某种修饰。修改方案已部分记录在 Wikipedia 上。 (参见“字符串常量”)。

无论如何,如果您希望以相同的方式处理程序集文件中的文字,则需要安排将文字以相同的方式放置在目标文件中。老实说,我不知道汇编程序可能有什么(如果有的话)机制。将对象放在“COMDAT”部分可能很容易——根据字符串内容(并以适当的方式修改)获取对象的名称是另一回事。

除非有一些汇编指令/关键字专门支持这种情况,否则我认为您可能不走运。当然可能有一个,但我对 ml.exe 已经很生疏了,根本不知道,快速浏览一下 ml.exe 的 MSDN 文档并没有什么都没有。

但是,如果您愿意将字符串文字放在 C 文件中,并通过 extern 在汇编代码中引用它们,它应该可以工作。然而,这基本上是 Mark Ransom 在他对该问题的评论中所提倡的。

关于c++ - C++ 编译器如何合并相同的字符串文字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6281835/

相关文章:

c++ - VS 2010 中的 SFML 错误

c++ - 在 Visual C++ 中删除调用后检测到堆损坏?

perl - 如何编译我的 Perl 脚本以减少启动时间?

c++ - iphone 编译器继承了模板化基类,传递类型没有及时扩展(看看)

c++ - 命名?模板、函数中的参数

c++ - 底层 std::array 的正确类型

C++ 非阻塞异步定时器

c++ - 为什么 C++ 标准库不包含哈希表实现?

c++ - C/C++ 编译器如何根据运算符的优先级和结合性来分离标记?

c++ - 如何使用 SimpleBlobDetector 获取 blob 的额外信息?