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

Jav*_*Man 15 c++ compiler-construction linker visual-c++

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

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

Mic*_*urr 9

(注意以下内容仅适用于MSVC)

我的第一个答案是误导,因为我认为字面合并是链接器完成的魔术(并且/GF只有链接器才需要标记).

然而,这是一个错误.事实证明链接器在合并字符串文字方面几乎没有特别的参与 - 当发生/GF给编译器的选项时,它会将字符串文字放在目标文件的"COMDAT"部分中,其对象名称基于内容字符串文字.因此编译步骤/GF需要标志,而不是链接步骤.

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

char* another_string = "this is a string";
Run Code Online (Sandbox Code Playgroud)

将在目标文件中具有以下内容:

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      
Run Code Online (Sandbox Code Playgroud)

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

请注意,字符串文字对象的名称显然基于文字字符串的内容,但有一些错位.我怀疑任何地方都有记录(但是谁知道 - 也许有人对它进行了逆向设计).

无论如何,如果你想要以相同的方式处理程序集文件中的文字,你需要安排文字以相同的方式放在目标文件中.老实说,我不知道汇编程序可能有什么(如果有的话)机制.将对象放在"COMDAT"部分可能非常简单 - 将对象的名称基于字符串内容(并以适当的方式修改)是另一个故事.

除非有一些专门支持这种情况的汇编指令/关键字,否则我认为你可能会失败.当然可能有一个,但我已经足够生气了ml.exe,不知道,快速浏览一下这些吝啬的MSDN文档ml.exe没有任何跳出来.

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