變數如何初始化,才能更有效率?通過查看vc、gcc編譯器的反組譯碼代碼查看不同方法初始化的效率區別。其中windows的編譯器cl的版本是Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86,gcc的版本是4.5.3。
原始碼:
void funA(){char *str1="helloworld";}void funB(){char str2[]="helloworld";}void funC(){char str3[11]="helloworld";}void funD(){char str4[11];str4[0]='h';str4[1]='e';str4[2]='l';str4[3]='l';str4[4]='o';str4[5]='w';str4[6]='o';str4[7]='r';str4[8]='l';str4[9]='d';str4[10]='\0';}void main(){funA();funB();funC();funD();}
1、VC編譯:vc產生彙編代碼: cl /FA varInit.c
TITLED:\5test\VarInit\varInit.c.386Pinclude listing.incif @Version gt 510.model FLATelse_TEXTSEGMENT PARA USE32 PUBLIC 'CODE'_TEXTENDS_DATASEGMENT DWORD USE32 PUBLIC 'DATA'_DATAENDSCONSTSEGMENT DWORD USE32 PUBLIC 'CONST'CONSTENDS_BSSSEGMENT DWORD USE32 PUBLIC 'BSS'_BSSENDS_TLSSEGMENT DWORD USE32 PUBLIC 'TLS'_TLSENDSFLATGROUP _DATA, CONST, _BSSASSUMECS: FLAT, DS: FLAT, SS: FLATendifPUBLIC_funA_DATASEGMENT$SG32DB'helloworld', 00H_DATAENDS_TEXTSEGMENT_str1$ = -4_funAPROC NEAR; File D:\5test\VarInit\varInit.c; Line 2pushebpmovebp, esppushecx; Line 3movDWORD PTR _str1$[ebp], OFFSET FLAT:$SG32; Line 4movesp, ebppopebpret0_funAENDP_TEXTENDSPUBLIC_funB_DATASEGMENTORG $+1$SG36DB'helloworld', 00H_DATAENDS_TEXTSEGMENT_str2$ = -12_funBPROC NEAR; Line 7pushebpmovebp, espsubesp, 12; 0000000cH; Line 8moveax, DWORD PTR $SG36movDWORD PTR _str2$[ebp], eaxmovecx, DWORD PTR $SG36+4movDWORD PTR _str2$[ebp+4], ecxmovdx, WORD PTR $SG36+8movWORD PTR _str2$[ebp+8], dxmoval, BYTE PTR $SG36+10movBYTE PTR _str2$[ebp+10], al; Line 9movesp, ebppopebpret0_funBENDP_TEXTENDSPUBLIC_funC_DATASEGMENTORG $+1$SG40DB'helloworld', 00H_DATAENDS_TEXTSEGMENT_str3$ = -12_funCPROC NEAR; Line 12pushebpmovebp, espsubesp, 12; 0000000cH; Line 13moveax, DWORD PTR $SG40movDWORD PTR _str3$[ebp], eaxmovecx, DWORD PTR $SG40+4movDWORD PTR _str3$[ebp+4], ecxmovdx, WORD PTR $SG40+8movWORD PTR _str3$[ebp+8], dxmoval, BYTE PTR $SG40+10movBYTE PTR _str3$[ebp+10], al; Line 14movesp, ebppopebpret0_funCENDP_TEXTENDSPUBLIC_funD_TEXTSEGMENT_str4$ = -12_funDPROC NEAR; Line 17pushebpmovebp, espsubesp, 12; 0000000cH; Line 19movBYTE PTR _str4$[ebp], 104; 00000068H; Line 20movBYTE PTR _str4$[ebp+1], 101; 00000065H; Line 21movBYTE PTR _str4$[ebp+2], 108; 0000006cH; Line 22movBYTE PTR _str4$[ebp+3], 108; 0000006cH; Line 23movBYTE PTR _str4$[ebp+4], 111; 0000006fH; Line 24movBYTE PTR _str4$[ebp+5], 119; 00000077H; Line 25movBYTE PTR _str4$[ebp+6], 111; 0000006fH; Line 26movBYTE PTR _str4$[ebp+7], 114; 00000072H; Line 27movBYTE PTR _str4$[ebp+8], 108; 0000006cH; Line 28movBYTE PTR _str4$[ebp+9], 100; 00000064H; Line 29movBYTE PTR _str4$[ebp+10], 0; Line 30movesp, ebppopebpret0_funDENDP_TEXTENDSPUBLIC_main_TEXTSEGMENT_mainPROC NEAR; Line 33pushebpmovebp, esp; Line 34call_funA; Line 35call_funB; Line 36call_funC; Line 37call_funD; Line 38popebpret0_mainENDP_TEXTENDSEND
2、cygwin環境內,GCC編譯產生彙編代碼: gcc -S varInit.c
.file"varInit.c".section .rdata,"dr"LC0:.ascii "helloworld\0".text.globl _funA.def_funA;.scl2;.type32;.endef_funA:pushl%ebpmovl%esp, %ebpsubl$16, %espmovl$LC0, -4(%ebp)leaveret.globl _funB.def_funB;.scl2;.type32;.endef_funB:pushl%ebpmovl%esp, %ebpsubl$16, %espmovl$1819043176, -11(%ebp)movl$1919907695, -7(%ebp)movw$25708, -3(%ebp)movb$0, -1(%ebp)leaveret.globl _funC.def_funC;.scl2;.type32;.endef_funC:pushl%ebpmovl%esp, %ebpsubl$16, %espmovl$1819043176, -11(%ebp)movl$1919907695, -7(%ebp)movw$25708, -3(%ebp)movb$0, -1(%ebp)leaveret.globl _funD.def_funD;.scl2;.type32;.endef_funD:pushl%ebpmovl%esp, %ebpsubl$16, %espmovb$104, -11(%ebp)movb$101, -10(%ebp)movb$108, -9(%ebp)movb$108, -8(%ebp)movb$111, -7(%ebp)movb$119, -6(%ebp)movb$111, -5(%ebp)movb$114, -4(%ebp)movb$108, -3(%ebp)movb$100, -2(%ebp)movb$0, -1(%ebp)leaveret.def___main;.scl2;.type32;.endef.globl _main.def_main;.scl2;.type32;.endef_main:pushl%ebpmovl%esp, %ebpandl$-16, %espcall___maincall_funAcall_funBcall_funCcall_funDmovl%ebp, %esppopl%ebpret
總體來看,第一種方式定義效率是最高的,因為字串直接定義在代碼的資料區段裡,然後指向寄存器就行了;第二、三種說明不論是否定義數組大小,執行效率是一樣的,所以如果字串直接初始化,還是不定義大小的好,免得數錯長度;第四種可以看到,在只定義局部變數的時候,如果不初始化,兩種平台根本都不會調用彙編代碼來幹些什麼。所以,從效率角度考慮,能不初始化就不初始化,如果要初始化,盡量在定義的時候初始化。字串儲存的時候,盡量使用4的整數倍長度,哪怕多寫一兩個\0,可以減少彙編指令的個數,長度11的時候,用了4*2+2+1這樣來儲存字串,如果多寫一個\0,就可以減少一條彙編指令了。沒在64位機上驗證,不過應該可以一條彙編指令儲存8個位元組的字元吧。
對比兩個平台的彙編代碼來看,vc編譯的彙編代碼注釋要詳細一些。但是vc平台的對應第二、三種初始化的操作,先把臨時變數存在eax裡,然後存在字串變數裡;而gcc中,直接從ebp裡取,存在對應的記憶體裡,每一次儲存少一條指令。