#include<stdio.h>
#include<stdlib.h>
int main(int argc, char** argv) {
char *str5=malloc(10);
*str5="xxxxx\0";
printf("%s\n",str5);
return 0;
}
编译成以下程序集(使用“gcc source.c”):
=> 0x555555555179 <main+4>: sub rsp,0x20
0x55555555517d <main+8>: mov DWORD PTR [rbp-0x14],edi
0x555555555180 <main+11>: mov QWORD PTR [rbp-0x20],rsi
0x555555555184 <main+15>: mov edi,0xa
0x555555555189 <main+20>: call 0x555555555040 <malloc@plt>
0x55555555518e <main+25>: mov QWORD PTR [rbp-0x8],rax
0x555555555192 <main+29>: lea rax,[rip+0xe6b] # 0x555555556004
0x555555555199 <main+36>: mov edx,eax
0x55555555519b <main+38>: mov rax,QWORD PTR [rbp-0x8]
0x55555555519f <main+42>: mov BYTE PTR [rax],dl
0x5555555551a1 <main+44>: mov rax,QWORD PTR [rbp-0x8]
0x5555555551a5 <main+48>: mov rdi,rax
0x5555555551a8 <main+51>: call 0x555555555030 <puts@plt>
0x5555555551ad <main+56>: mov eax,0x0
0x5555555551b2 <main+61>: leave
0x5555555551b3 <main+62>: ret
0x5555555551b4 <_fini>: sub rsp,0x8
0x5555555551b8 <_fini+4>: add rsp,0x8
0x5555555551bc <_fini+8>: ret
编辑- 澄清一下,我不是问如何正确复制或分配字符串 - 我知道如何做到这一点。我问为什么这套特定的指令以这种方式编译。所选答案很好地回答了这个问题。 -结束编辑。
实际发生的情况: 因此,在 main+42 上,它将 $dl (字符串常量“xxxxx”的地址的最低字节加载到 $rax 指向的地址中,即我的变量 str5。这最终只是一个垃圾字符,并且字符串常量的其余部分永远不会被复制。编译器会发出以下警告,这可能是相关的,但我不明白如何:
source.c:6:14: warning: assignment to ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
我期望发生什么: 字符串常量“xxxxx”被加载到str5指向的地址中。然后,str5指向的字符串被打印到屏幕上。 为什么 gcc 这样编译这段代码?
在 C
*str5="xxxxx\0";
中不复制字符串。
这个操作其实是:
"xxxxx\0"
char
(这是一个整数)malloc
分配的内存的第一个字符分配为该整数值打印时,第一个字符是字符形式的整数。其余字符未初始化,此代码调用未定义的行为。
如果你想复制字符串文字,你需要
strcpy(str, "xxxxx");
(字符串文字将有空终止字符,你不需要自己把它放在那里)
所以编译器是正确的,它正在为您编写的程序生成代码。