我正在研究char* c = "thomas";
和char c[] = "thomas";
之间的差异。我在这里看到了有关这方面的问题,在尝试理解答案时,我想通过查看装配来检查我是对的。并且出现了一些问题。
以下是我的想法:
char* c = ...
:字符分配在静态内存的某处(从程序的角度来看),以及代码。这就是它应该被标记为const
的原因。字符串可以打印但不能修改。
char c[] = ...
:与1.相同,除了在调用函数时,字符被复制到堆栈中的数组中,因此可以修改等等。
我想检查这个,所以我做了这个C代码:
#include <stdio.h>
int main(){
char c [] = "thomas blabljbflkjbsdflkjbds";
printf("%s\n", c);
}
查看生成的程序集:
0x400564 <main>: push rbp
0x400565 <main+1>: mov rbp,rsp
0x400568 <main+4>: sub rsp,0x30
0x40056c <main+8>: mov rax,QWORD PTR fs:0x28
0x400575 <main+17>: mov QWORD PTR [rbp-0x8],rax
0x400579 <main+21>: xor eax,eax
0x40057b <main+23>: mov DWORD PTR [rbp-0x30],0x6978616d
0x400582 <main+30>: mov DWORD PTR [rbp-0x2c],0x6220656d
0x400589 <main+37>: mov DWORD PTR [rbp-0x28],0x6c62616c
0x400590 <main+44>: mov DWORD PTR [rbp-0x24],0x6c66626a
0x400597 <main+51>: mov DWORD PTR [rbp-0x20],0x73626a6b
0x40059e <main+58>: mov DWORD PTR [rbp-0x1c],0x6b6c6664
0x4005a5 <main+65>: mov DWORD PTR [rbp-0x18],0x7364626a
0x4005ac <main+72>: mov BYTE PTR [rbp-0x14],0x0
0x4005b0 <main+76>: lea rax,[rbp-0x30]
0x4005b4 <main+80>: mov rdi,rax
0x4005b7 <main+83>: call 0x400450 <puts@plt>
0x4005bc <main+88>: mov rdx,QWORD PTR [rbp-0x8]
0x4005c0 <main+92>: xor rdx,QWORD PTR fs:0x28
0x4005c9 <main+101>: je 0x4005d0 <main+108>
所以字符被复制到堆栈中,这就是我的想法。
问题:
字符按地址0x6978616d, 0x6220656d
的字节存储,依此类推。为什么它们不是在数组中连续分配的?简单优化编译器?
char*
的行为不像数组,为什么c[10]
不是字符串的第11个字符。 然而它没有解释原因char * c =“thomas blabljbflkjbsdflkjbds”; printf(“%s \ n”,c);
的工作原理。 (注意[] - &gt; *)。我想printf
按字符读取字符直到达到0,所以只知道c (i.e &c[0])
它如何访问c[10]
? (因为不连续而且这个时间字符没有复制到堆栈上的数组这一事实)
我希望我很清楚,如果你要求/不理解一点,我可以重新制定。感谢
答案 0 :(得分:3)
1:0x6978616d
,0x6220656d
不是地址,而是字符串中的数据。当转换为从十六进制转换为ascii时,0x6978616d
= moht
,0x6220656d
= b sa
。
2:在函数调用中使用时,数组会衰减为指针。因此,无论printf
是数组还是指针,c
都会收到指向char的指针。
答案 1 :(得分:1)
编译器实际上可能会选择将字符数组初始化编译为只读存储的副本,但正如Klas建议的那样,在您的示例中不会发生这种情况。
下面是一个代码实例(使用gcc)。将STR
的定义更改为各种长度的字符串并查看汇编输出的差异可能会很有启发性。
/* 99 characters */
#define STR "123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789"
void observe(const char *);
void test1() {
char *str = STR;
observe(str);
}
void test2() {
char str[] = STR;
observe(str);
}
大会:
.section .rodata.str1.4,"aMS",@progbits,1
.align 4
.LC0:
.string "123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789"
.text
test2:
pushl %ebp
movl $25, %ecx
movl %esp, %ebp
subl $136, %esp
movl %esi, -8(%ebp)
movl $.LC0, %esi
movl %edi, -4(%ebp)
leal -108(%ebp), %edi
rep movsl
leal -108(%ebp), %eax
movl %eax, (%esp)
call observe
movl -8(%ebp), %esi
movl -4(%ebp), %edi
movl %ebp, %esp
popl %ebp
ret
test1:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $.LC0, (%esp)
call observe
leave
ret