编译器代码生成比较

Fer*_*eak 4 c compiler-construction assembly gcc visual-c++

好的,所以一切都从这里开始:无符号整数和无符号字符保持相同的值但行为不同为什么?

我编写了以下应用程序来了解幕后发生的事情(即编译器如何处理此问题).

#include <stdio.h>

int main()
{
  {
  unsigned char k=-1;
  if(k==-1)
  {
    puts("uc ok\n");
  }
  }

  {
  unsigned int k=-1;
  if(k==-1)
  {
    puts("ui ok");
  }
  }
}
Run Code Online (Sandbox Code Playgroud)

虽然用GCC编译它,如:

gcc -O0 -S -masm=intel h.c 
Run Code Online (Sandbox Code Playgroud)

我得到以下程序集文件:

    .file   "h.c"
    .intel_syntax noprefix
    .section        .rodata
.LC0:
    .string "ui ok"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    push    rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    mov     rbp, rsp
    .cfi_def_cfa_register 6
    sub     rsp, 16
    mov     BYTE PTR [rbp-1], -1
    mov     DWORD PTR [rbp-8], -1
    cmp     DWORD PTR [rbp-8], -1
    jne     .L3
    mov     edi, OFFSET FLAT:.LC0
    call    puts
.L3:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
    .section        .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,第一次检查并非偶然.

但是,如果我用Microsoft Visual C++(2010)编译相同的东西,我得到(我已经从这个列表中切掉了很多垃圾,这就是为什么它不那么有效):

00B81780  push        ebp  
00B81781  mov         ebp,esp  
00B81783  sub         esp,0D8h  
00B81789  push        ebx  
00B8178A  push        esi  
00B8178B  push        edi  
00B8178C  lea         edi,[ebp-0D8h]  
00B81792  mov         ecx,36h  
00B81797  mov         eax,0CCCCCCCCh  
00B8179C  rep stos    dword ptr es:[edi]  
00B8179E  mov         byte ptr [k],0FFh  
00B817A2  movzx       eax,byte ptr [k]  
00B817A6  cmp         eax,0FFFFFFFFh  
00B817A9  jne         wmain+42h (0B817C2h)  
00B817AB  mov         esi,esp  
00B817AD  push        offset string "uc ok\n" (0B857A8h)  
00B817B2  call        dword ptr [__imp__puts (0B882ACh)]  
00B817B8  add         esp,4  
00B817BB  cmp         esi,esp  
00B817BD  call        @ILT+435(__RTC_CheckEsp) (0B811B8h)  
00B817C2  mov         dword ptr [k],0FFFFFFFFh  
00B817C9  cmp         dword ptr [k],0FFFFFFFFh  
00B817CD  jne         wmain+66h (0B817E6h)  
00B817CF  mov         esi,esp  
00B817D1  push        offset string "ui ok" (0B857A0h)  
00B817D6  call        dword ptr [__imp__puts (0B882ACh)]  
00B817DC  add         esp,4  
00B817DF  cmp         esi,esp  
00B817E1  call        @ILT+435(__RTC_CheckEsp) (0B811B8h)  
Run Code Online (Sandbox Code Playgroud)

问题是:为什么会这样?为什么海湾合作委员会"跳过"第一个IF,我怎么能强迫GCC不跳过它?优化被禁用,但它似乎仍然优化了一些东西......

unw*_*ind 7

我的猜测(我不是GCC的开发人员)是它做了足够的静态分析来向自己证明第一个if测试永远不会是真的.

这不应该太难,因为初始化和测试之间没有代码,任何副作用或外部实体都无法改变变量.

只是为了好奇,尝试制作变量static和/或volatile查看是否有任何变化.