在以下代码段中
char *str1 = "abcd";
char str2[] = "defg";
我意识到第一个语句将指针存储在可执行文件的readonly部分中的字符串文字中,而第二个语句存储到读写部分的第二个语句。 在检查生成的指令时,我验证第一个指针将指针存储到" abcd"在rodata部分到str1。
有趣的是第二个陈述。编译器插入代码将值存储到
中char *str1 = "abcd";
8048420: c7 44 24 10 20 85 04 movl $0x8048520,0x10(%esp)
8048427: 08
char str2[] = "defg";
8048428: c7 44 24 17 64 65 66 movl $0x67666564,0x17(%esp)
804842f: 67
8048430: c6 44 24 1b 00 movb $0x0,0x1b(%esp)
编译器如何决定何时执行以下操作?
注意:我正在运行一个精确的32个流浪者,带有调试符号的gcc和-O0
答案 0 :(得分:1)
当使用编译时聚合值(不限于字符串文字)初始化内存中的聚合对象时,编译器始终可以选择
在编译时在只读数据部分预构建完整的初始化程序,然后在运行时使用memcpy
将整个内容复制到可修改的目标值中。
生成将直接构建目标值的代码"就地"在运行时逐件。
基本上,第一个是基于数据的""方法,第二个是基于代码的"做法。在您的情况下,编译器使用基于代码的解决方案,可能是因为文字很短。使用较长的文字,我怀疑它最终将切换到第一种方法。
有人可能会想到,在某些情况下,某些编译器可能会使用混合方法:部分数据在某处预先构建,memcpy
- 从那里开始,其余数据构建在飞。
答案 1 :(得分:1)
如果你的
char str2[] = "defg";
定义在函数内部,然后编译器将生成将数据放入堆栈的指令(忽略可能的优化,例如将值保持在寄存器中)。这与其他自动(堆栈)变量一样。
它还可以选择将数据从其他地方复制到堆栈而不是例如将数据值作为指令的立即操作数。它可能会选择为更长的字符串执行此操作以避免代码膨胀。
无论编译器做什么,下一次调用函数时都不能看到对str2
内容的修改(就像其他自动变量一样)。
如果str2
是全局的(给它静态存储持续时间),则数据将以读/写数据段结束。如果在函数内部给出数组静态存储持续时间,也会发生这种情况,如
static char str2[] = "defg";
使用字符串文字初始化指针时,如
char *s = "defg";
,数据最终在只读数据段中,指针本身如何使用数据的地址初始化的规则与上方。