代码之家  ›  专栏  ›  技术社区  ›  skiwarz

C代码编译成不正确的指令

gcc c
  •  -3
  • skiwarz  · 技术社区  · 2 年前
    #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;
    }
    

    编译成以下程序集(使用“gccsource.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\0”的ADDRESS的最低字节)加载到$rax指向的地址中,这就是我的变量str5。这最终只是一个垃圾字符,字符串常量的其余部分永远不会被复制。编译器发出以下警告,这可能是相关的,但我不明白是怎么回事: source.c:6:14: warning: assignment to ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]

    我期望发生的事情: 字符串常量“xxxxx\0”加载到str5指向的地址中。然后,str5指向的字符串被打印到屏幕上。 为什么gcc以这种方式编译这些代码?

    1 回复  |  直到 2 年前
        1
  •  4
  •   gulpr    2 年前

    在C中 *str5="xxxxx\0"; 不复制字符串。

    这个操作实际上是:

    • 获取字符串文字的地址 "xxxxx\0"
    • 将此地址转换为 char (这是一个整数)
    • 分配的第一个字符 malloc 具有此整数值的内存

    打印时,第一个字符是字符形式的整数。其余字符未初始化,此代码调用未定义的行为。

    如果你想复制字符串文字,你需要 strcpy(str, "xxxxx"); (字符串文字将具有null终止字符,您不需要自己将其放在那里) 所以编译器是正确的,它正在为您编写的程序生成代码。