我读到字符串字面值总是存储在只读内存中,这很有道理。
然而,如果我使用一个字符串字面值来初始化字符数组,它仍然会将字符串字面值存储在只读内存中,然后将其复制到字符数组的内存位置。
我的问题是,在这种情况下,为什么要在第一次存储字符串字面值时存储在只读内存中,而不是直接存储在字符数组的内存位置中。
我读到字符串字面值总是存储在只读内存中,这很有道理。
然而,如果我使用一个字符串字面值来初始化字符数组,它仍然会将字符串字面值存储在只读内存中,然后将其复制到字符数组的内存位置。
我的问题是,在这种情况下,为什么要在第一次存储字符串字面值时存储在只读内存中,而不是直接存储在字符数组的内存位置中。
int sum() {
char arr[] = "ab";
return arr[0] + arr[1];
}
sum():
mov eax, 195
ret
return 195;
,通过求和两个ASCII字符a
和b
得到结果。
void consume(const char*);
void short_string() {
char arr[] = "short str";
consume(arr);
}
short_string():
sub rsp, 24
movabs rax, 8391086215229565043
mov qword ptr [rsp + 8], rax
mov word ptr [rsp + 16], 114
lea rdi, [rsp + 8]
call consume(char const*)@PLT
add rsp, 24
ret
short str
非常短,因此将其ASCII字节视为数字8391086215229565043
,并直接将其内存mov
到堆栈上。使用指向堆栈内存的指针调用consume()
函数。
void long_string() {
char arr[] = "Lorem ipsum dolor [...] est laborum.";
consume(arr);
}
long_string():
push rbx
sub rsp, 448
lea rsi, [rip + .L__const.long_string().arr]
mov rbx, rsp
mov edx, 446
mov rdi, rbx
call memcpy@PLT
mov rdi, rbx
call consume(char const*)@PLT
add rsp, 448
pop rbx
ret
.L__const.long_string().arr:
.asciz "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
查看{{link1:使用Compiler Explorer的实时示例}}
consume(arr)
时我们要获取它的地址。由于数组存在于静态内存中,我们通过sub rsp, 448
将堆栈增加448字节,然后调用memcpy
将448个字符串字面量字节复制到堆栈上。如果没有这个静态内存中的字符串字面量,我们将不得不生成大量代码将其放在那里,而不仅仅是调用memcpy
函数。 - Jan Schultkestatic char long_string[] = "...";
或者全局变量:它们可以像静态存储中的任何其他非常量数组一样存在于可读写的.data
段中。此外,这与源代码中的字符串字面量无关。我们可以通过int foo[] = {1,2,3,4,...,99};
来达到相同的效果,并且编译器可以选择从.rodata
段进行memcpy,或者在数组需要存在于堆栈上时存储立即数,否则有其他选项。(@HumblePenguin) - Peter Cordes
-fPIC
选项),这样做的唯一方式就是将字符串存储在指令的“立即”(payload)值中。但实际上,这与将其存储在只读内存中几乎没有太大区别... 事实上,除了一些低级技术细节(指令缓存,数据缓存)之外,它几乎没有任何区别。 - Andrej Podzimekchar const[N]
,其中N
是一个正整数。编译器可以按照自己的意愿处理它。C++所要表达的就是,“不要对这个对象进行写操作”。 - bitmaskchar foo[10] = "FooFoo"
。 - Marek Rchar foo[10] = "FooFoo"
。 - undefined