string数据存储在哪里?

我写了一个小c程序:

#include <stdio.h> int main() { char s[] = "Hello, world!"; printf("%s\n", s); return 0; } 

编译(在我的Linux机器上):

  .file "hello.c" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $32, %rsp movq %fs:40, %rax movq %rax, -8(%rbp) xorl %eax, %eax movl $1819043144, -32(%rbp) movl $1998597231, -28(%rbp) movl $1684828783, -24(%rbp) movw $33, -20(%rbp) leaq -32(%rbp), %rax movq %rax, %rdi call puts movl $0, %eax movq -8(%rbp), %rdx xorq %fs:40, %rdx je .L3 call __stack_chk_fail .L3: leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2" .section .note.GNU-stack,"",@progbits 

我不明白汇编代码,但我看不到任何string消息。 那么可执行文件如何知道要打印什么?

它在这里:

 movl $1819043144, -32(%rbp) ; 1819043144 = 0x6C6C6548 = "lleH" movl $1998597231, -28(%rbp) ; 1998597231 = 0x77202C6F = "w ,o" movl $1684828783, -24(%rbp) ; 1684828783 = 0x646C726F = "dlro" movw $33, -20(%rbp) ; 33 = 0x0021 = "\0!" 

在这种特殊情况下,编译器生成内联指令,在调用printf之前生成文字字符串常量。 当然,在其他情况下,它可能不会这样做,但可能会将字符串常量存储在另一部分内存中。 底线:你不能对编译器如何或在何处生成和存储字符串文字做任何假设。

字符串在这里:

 movl $1819043144, -32(%rbp) movl $1998597231, -28(%rbp) movl $1684828783, -24(%rbp) 

这将一堆值复制到堆栈。 这些价值恰巧是你的字符串。

字符串常量存储在应用程序的二进制文件中。 究竟在哪里到你的编译器。

大会没有“字符串”的概念。 因此,“字符串”实际上是一块记忆。 该字符串存储在内存中的某处(直到编译器),那么你可以使用它的内存地址(指针)来处理这块数据。

如果你的字符串是常量 ,编译器可能想把它作为常量使用,而不是把它存储到内存中,速度更快。 正如Paul R指出的那样:

 movl $1819043144, -32(%rbp) movl $1998597231, -28(%rbp) movl $1684828783, -24(%rbp) 

你不能假设编译器如何处理你的字符串。

除了上面的内容,编译器可以看到你的字符串不能被直接引用(即不能有任何有效的字符串指针),这就是为什么它可以直接拷贝它。 但是,如果你分配一个字符指针,而不是

char *s = "Hello, world!";

编译器会在内存中的某个地方初始化一个字符串,因为你现在可以指向它了。 这个修改在我的机器上产生:

 .LC0: .string "Hello, world!" .text .globl main .type main, @function 

关于字符串文字可以做一个假设:如果一个指针被初始化为一个文字,它将指向一个存储在某处的静态字符数组。 因此指针在程序的任何部分都是有效的,比如你可以返回一个指向在函数中初始化的字符串的指针,它仍然是有效的。