编译器对通过指针进行迭代和通过索引进行迭代是否产生相同代码?问题来自于《The C++ Program Language》第五章习题8。
测试代码如下:(采用vc.net向导自动生成控制台应用程序)
#include "stdafx.h"
void fi (char v[]) // line 5
{
for (int i = 0; v[i] != 0; ++i) {
v[i] += 1;
}
}
void fp (char v[]) // line 12
{
for (char *p=v; *p != 0; ++p) {
*pa += 1;
}
}
int _tmain(int argc, _TCHAR* argv[]) // line 19
{
char a[8] = {'a', 'b', 'c', 'd', 'e', 'f', 'g' , 'h'};
fp (a);
fi (a);
return 0;
}
在vc++7.net上使用参数FA(仅列出程序集),产生的汇编代码如下(未优化):
; Listing generated by Microsoft (R) Optimizing Compiler Version 13.10.3077
TITLE ./5_8.cpp
.386P
include listing.inc
... ... ... ...
INCLUDELIB LIBCD
INCLUDELIB OLDNAMES
PUBLIC ?fi@@YAXQAD@Z ; fi,函数fi的代码开始
EXTRN __RTC_InitBase:NEAR
EXTRN __RTC_Shutdown:NEAR
; COMDAT rtc$IMZ
; File d:/vsproject/5_8/5_8.cpp
rtc$IMZ SEGMENT
__RTC_InitBase.rtc$IMZ DD FLAT:__RTC_InitBase
rtc$IMZ ENDS
; COMDAT rtc$TMZ
rtc$TMZ SEGMENT
__RTC_Shutdown.rtc$TMZ DD FLAT:__RTC_Shutdown
; Function compile flags: /Odt /RTCsu /ZI
rtc$TMZ ENDS
; COMDAT ?fi@@YAXQAD@Z
_TEXT SEGMENT
_i$10435 = -8 ; size = 4
_v$ = 8 ; size = 4
?fi@@YAXQAD@Z PROC NEAR ; fi, COMDAT
; Line 6
push ebp
mov ebp, esp
sub esp, 204 ; 000000ccH
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-204]
mov ecx, 51 ; 00000033H
mov eax, -858993460 ; ccccccccH
rep stosd
; Line 7 // ********************************
mov DWORD PTR _i$10435[ebp], 0
jmp SHORT $L10436
$L10437:
mov eax, DWORD PTR _i$10435[ebp]
add eax, 1
mov DWORD PTR _i$10435[ebp], eax
$L10436:
mov eax, DWORD PTR _v$[ebp]
add eax, DWORD PTR _i$10435[ebp]
movsx ecx, BYTE PTR [eax]
test ecx, ecx
je SHORT $L10434
; Line 8
mov eax, DWORD PTR _v$[ebp]
add eax, DWORD PTR _i$10435[ebp]
movsx ecx, BYTE PTR [eax]
add ecx, 1
mov edx, DWORD PTR _v$[ebp]
add edx, DWORD PTR _i$10435[ebp]
mov BYTE PTR [edx], cl
; Line 9
jmp SHORT $L10437
$L10434:
; Line 10
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
?fi@@YAXQAD@Z ENDP ; fi
_TEXT ENDS
PUBLIC ?fp@@YAXQAD@Z ; fp,函数fp的代码开始
; Function compile flags: /Odt /RTCsu /ZI
; COMDAT ?fp@@YAXQAD@Z
_TEXT SEGMENT
_p$10442 = -8 ; size = 4
_v$ = 8 ; size = 4
?fp@@YAXQAD@Z PROC NEAR ; fp, COMDAT
; Line 13
push ebp
mov ebp, esp
sub esp, 204 ; 000000ccH
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-204]
mov ecx, 51 ; 00000033H
mov eax, -858993460 ; ccccccccH
rep stosd
; Line 14 // ******************************
mov eax, DWORD PTR _v$[ebp]
mov DWORD PTR _p$10442[ebp], eax
jmp SHORT $L10443
$L10444:
mov eax, DWORD PTR _p$10442[ebp]
add eax, 1
mov DWORD PTR _p$10442[ebp], eax
$L10443:
mov eax, DWORD PTR _p$10442[ebp]
movsx ecx, BYTE PTR [eax]
test ecx, ecx
je SHORT $L10441
; Line 15
mov eax, DWORD PTR _p$10442[ebp]
movsx ecx, BYTE PTR [eax]
add ecx, 1
mov edx, DWORD PTR _p$10442[ebp]
mov BYTE PTR [edx], cl
; Line 16
jmp SHORT $L10444
$L10441:
; Line 17
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
?fp@@YAXQAD@Z ENDP ; fp
_TEXT ENDS
PUBLIC _main
EXTRN @_RTC_CheckStackVars@8:NEAR
EXTRN __RTC_CheckEsp:NEAR
; Function compile flags: /Odt /RTCsu /ZI
; COMDAT _main
... ... ... ...
END
注意上面Line8和Line15前后的汇编语句,就是一模一样的。也就是说,在没有任何优化的情况下,通过指针进行迭代和通过索引进行迭代将产生相同代码。
如果进行全面的优化,结果会怎么样呢?对同一个文件,在vc7.net采用RELEASE,打开全局优化,产生的汇编代码如下。可以看到,两个函数的代码仍然是相同的。
; Listing generated by Microsoft (R) Optimizing Compiler Version 13.10.3077
TITLE ./5_8.cpp
.386P
include listing.inc
... ... ... ...
INCLUDELIB LIBC
INCLUDELIB OLDNAMES
PUBLIC ?fi@@YAXQAD@Z ; fi,函数fi的代码开始
; Function compile flags: /Ogty
; COMDAT ?fi@@YAXQAD@Z
_TEXT SEGMENT
_v$ = 8 ; size = 4
?fi@@YAXQAD@Z PROC NEAR ; fi, COMDAT
; File d:/vsproject/5_8/5_8.cpp
; Line 7
mov eax, DWORD PTR _v$[esp-4]
cmp BYTE PTR [eax], 0
je SHORT $L9624
npad 7
$L9622:
; Line 8
inc BYTE PTR [eax]
mov cl, BYTE PTR [eax+1]
inc eax
test cl, cl
jne SHORT $L9622
$L9624:
; Line 10
ret 0
?fi@@YAXQAD@Z ENDP ; fi
_TEXT ENDS
PUBLIC ?fp@@YAXQAD@Z ; fp,函数fp的代码开始
; Function compile flags: /Ogty
; COMDAT ?fp@@YAXQAD@Z
_TEXT SEGMENT
_v$ = 8 ; size = 4
?fp@@YAXQAD@Z PROC NEAR ; fp, COMDAT
; Line 14
mov eax, DWORD PTR _v$[esp-4]
cmp BYTE PTR [eax], 0
je SHORT $L9631
npad 7
$L9629:
; Line 15
inc BYTE PTR [eax]
mov cl, BYTE PTR [eax+1]
inc eax
test cl, cl
jne SHORT $L9629
$L9631:
; Line 17
ret 0
?fp@@YAXQAD@Z ENDP ; fp
_TEXT ENDS
PUBLIC _main
EXTRN ___security_cookie:DWORD
EXTRN @__security_check_cookie@4:NEAR
; Function compile flags: /Ogty
; COMDAT _main
... ... ... ...
END