编译器 (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/