字符串字面量的确切存储位置很大程度上取决于各个实现;唯一的要求是该字面量对整个程序可见,并且在程序启动时分配并保持到程序终止。
某些平台可能会将文字存储在不同的内存段中(例如.rodata)。
至于区别
char *name = "Adam";
和
char name2[] = "Adam";
图片可能会有所帮助。以下是我的特定系统上的情况:
Item Address 00 01 02 03
---- ------- -- -- -- --
"Adam" 0x400ac0 41 64 61 6d Adam
0x400ac4 00 22 41 64 ."Ad
name 0x7fff39dbdb78 c0 0a 40 00 ..@.
0x7fff39dbdb7c 00 00 00 00 ....
name2 0x7fff39dbdb70 41 64 61 6d Adam
0x7fff39dbdb74 00 7f 00 00 ....
字符串文字"Adam" 存储为char 的数组,从地址0x400ac0 开始(在我的系统上的.rodata 段中)。
变量name 是一个指向char 的指针,并且包含字符串文字的地址(我的系统是little-endian,所以地址读作“向后”)。
变量name2 是char 的数组,其内容是从字符串文字复制。
编辑
查看生成的机器代码可能更有帮助。采取以下程序:
#include <stdio.h>
int main( void )
{
char *name = "Adam";
char name2[] = "Adam";
printf("name = %s, name2 = %s\n", name, name2 );
return 0;
}
我在 SLES 10 系统上使用gcc 编译如下:
gcc -o name2 -std=c99 -pedantic -Wall -Werror name2.c -Wa,-aldh=name2.lst
这在 name2.lst 中给了我以下汇编器输出:
GAS LISTING /tmp/ccuuqqGI.s page 1
1 .file "name2.c"
2 .section .rodata
3 .LC0:
4 0000 4164616D .string "Adam"
4 00
5 .LC1:
6 0005 6E616D65 .string "name = %s, name2 = %s\n"
6 203D2025
6 732C206E
6 616D6532
6 203D2025
7 .text
8 .globl main
10 main:
11 .LFB2:
12 0000 55 pushq %rbp
13 .LCFI0:
14 0001 4889E5 movq %rsp, %rbp
15 .LCFI1:
16 0004 4883EC10 subq $16, %rsp
17 .LCFI2:
18 0008 48C745F8 movq $.LC0, -8(%rbp)
18 00000000
19 0010 8B050000 movl .LC0(%rip), %eax
19 0000
20 0016 8945F0 movl %eax, -16(%rbp)
21 0019 0FB60500 movzbl .LC0+4(%rip), %eax
21 000000
22 0020 8845F4 movb %al, -12(%rbp)
23 0023 488D55F0 leaq -16(%rbp), %rdx
24 0027 488B75F8 movq -8(%rbp), %rsi
25 002b BF000000 movl $.LC1, %edi
25 00
26 0030 B8000000 movl $0, %eax
26 00
27 0035 E8000000 call printf
27 00
28 003a B8000000 movl $0, %eax
28 00
29 003f C9 leave
30 0040 C3 ret
31 .LFE2:
如您所见,字符串文字"Adam" 和"name = %s, name2 = %s\n" 存储在.rodata 部分(用于只读数据项)。第 18 行将字符串文字的地址复制到 name,而第 19 到 22 行将字符串文字的 contents 复制到 name2。