从汇编看待变量初始化

变量如何初始化,才能更有效率?通过查看vc、gcc编译器的反汇编代码查看不同方法初始化的效率区别。其中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

 

 

	TITLE	D:\5test\VarInit\varInit.c

	.386P

include listing.inc

if @Version gt 510

.model FLAT

else

_TEXT	SEGMENT PARA USE32 PUBLIC 'CODE'

_TEXT	ENDS

_DATA	SEGMENT DWORD USE32 PUBLIC 'DATA'

_DATA	ENDS

CONST	SEGMENT DWORD USE32 PUBLIC 'CONST'

CONST	ENDS

_BSS	SEGMENT DWORD USE32 PUBLIC 'BSS'

_BSS	ENDS

_TLS	SEGMENT DWORD USE32 PUBLIC 'TLS'

_TLS	ENDS

FLAT	GROUP _DATA, CONST, _BSS

	ASSUME	CS: FLAT, DS: FLAT, SS: FLAT

endif

PUBLIC	_funA

_DATA	SEGMENT

$SG32	DB	'helloworld', 00H

_DATA	ENDS

_TEXT	SEGMENT

_str1$ = -4

_funA	PROC NEAR

; File D:\5test\VarInit\varInit.c

; Line 2

	push	ebp

	mov	ebp, esp

	push	ecx

; Line 3

	mov	DWORD PTR _str1$[ebp], OFFSET FLAT:$SG32

; Line 4

	mov	esp, ebp

	pop	ebp

	ret	0

_funA	ENDP

_TEXT	ENDS

PUBLIC	_funB

_DATA	SEGMENT

	ORG $+1

$SG36	DB	'helloworld', 00H

_DATA	ENDS

_TEXT	SEGMENT

_str2$ = -12

_funB	PROC NEAR

; Line 7

	push	ebp

	mov	ebp, esp

	sub	esp, 12					; 0000000cH

; Line 8

	mov	eax, DWORD PTR $SG36

	mov	DWORD PTR _str2$[ebp], eax

	mov	ecx, DWORD PTR $SG36+4

	mov	DWORD PTR _str2$[ebp+4], ecx

	mov	dx, WORD PTR $SG36+8

	mov	WORD PTR _str2$[ebp+8], dx

	mov	al, BYTE PTR $SG36+10

	mov	BYTE PTR _str2$[ebp+10], al

; Line 9

	mov	esp, ebp

	pop	ebp

	ret	0

_funB	ENDP

_TEXT	ENDS

PUBLIC	_funC

_DATA	SEGMENT

	ORG $+1

$SG40	DB	'helloworld', 00H

_DATA	ENDS

_TEXT	SEGMENT

_str3$ = -12

_funC	PROC NEAR

; Line 12

	push	ebp

	mov	ebp, esp

	sub	esp, 12					; 0000000cH

; Line 13

	mov	eax, DWORD PTR $SG40

	mov	DWORD PTR _str3$[ebp], eax

	mov	ecx, DWORD PTR $SG40+4

	mov	DWORD PTR _str3$[ebp+4], ecx

	mov	dx, WORD PTR $SG40+8

	mov	WORD PTR _str3$[ebp+8], dx

	mov	al, BYTE PTR $SG40+10

	mov	BYTE PTR _str3$[ebp+10], al

; Line 14

	mov	esp, ebp

	pop	ebp

	ret	0

_funC	ENDP

_TEXT	ENDS

PUBLIC	_funD

_TEXT	SEGMENT

_str4$ = -12

_funD	PROC NEAR

; Line 17

	push	ebp

	mov	ebp, esp

	sub	esp, 12					; 0000000cH

; Line 19

	mov	BYTE PTR _str4$[ebp], 104		; 00000068H

; Line 20

	mov	BYTE PTR _str4$[ebp+1], 101		; 00000065H

; Line 21

	mov	BYTE PTR _str4$[ebp+2], 108		; 0000006cH

; Line 22

	mov	BYTE PTR _str4$[ebp+3], 108		; 0000006cH

; Line 23

	mov	BYTE PTR _str4$[ebp+4], 111		; 0000006fH

; Line 24

	mov	BYTE PTR _str4$[ebp+5], 119		; 00000077H

; Line 25

	mov	BYTE PTR _str4$[ebp+6], 111		; 0000006fH

; Line 26

	mov	BYTE PTR _str4$[ebp+7], 114		; 00000072H

; Line 27

	mov	BYTE PTR _str4$[ebp+8], 108		; 0000006cH

; Line 28

	mov	BYTE PTR _str4$[ebp+9], 100		; 00000064H

; Line 29

	mov	BYTE PTR _str4$[ebp+10], 0

; Line 30

	mov	esp, ebp

	pop	ebp

	ret	0

_funD	ENDP

_TEXT	ENDS

PUBLIC	_main

_TEXT	SEGMENT

_main	PROC NEAR

; Line 33

	push	ebp

	mov	ebp, esp

; Line 34

	call	_funA

; Line 35

	call	_funB

; Line 36

	call	_funC

; Line 37

	call	_funD

; Line 38

	pop	ebp

	ret	0

_main	ENDP

_TEXT	ENDS

END


2、cygwin环境内,GCC编译生成汇编代码: gcc -S varInit.c

 

 

	.file	"varInit.c"

	.section .rdata,"dr"

LC0:

	.ascii "helloworld\0"

	.text

.globl _funA

	.def	_funA;	.scl	2;	.type	32;	.endef

_funA:

	pushl	%ebp

	movl	%esp, %ebp

	subl	$16, %esp

	movl	$LC0, -4(%ebp)

	leave

	ret

.globl _funB

	.def	_funB;	.scl	2;	.type	32;	.endef

_funB:

	pushl	%ebp

	movl	%esp, %ebp

	subl	$16, %esp

	movl	$1819043176, -11(%ebp)

	movl	$1919907695, -7(%ebp)

	movw	$25708, -3(%ebp)

	movb	$0, -1(%ebp)

	leave

	ret

.globl _funC

	.def	_funC;	.scl	2;	.type	32;	.endef

_funC:

	pushl	%ebp

	movl	%esp, %ebp

	subl	$16, %esp

	movl	$1819043176, -11(%ebp)

	movl	$1919907695, -7(%ebp)

	movw	$25708, -3(%ebp)

	movb	$0, -1(%ebp)

	leave

	ret

.globl _funD

	.def	_funD;	.scl	2;	.type	32;	.endef

_funD:

	pushl	%ebp

	movl	%esp, %ebp

	subl	$16, %esp

	movb	$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)

	leave

	ret

	.def	___main;	.scl	2;	.type	32;	.endef

.globl _main

	.def	_main;	.scl	2;	.type	32;	.endef

_main:

	pushl	%ebp

	movl	%esp, %ebp

	andl	$-16, %esp

	call	___main

	call	_funA

	call	_funB

	call	_funC

	call	_funD

	movl	%ebp, %esp

	popl	%ebp

	ret

 

总体来看,第一种方式定义效率是最高的,因为字符串直接定义在代码的数据段里,然后指向寄存器就行了;第二、三种说明不论是否定义数组大小,执行效率是一样的,所以如果字符串直接初始化,还是不定义大小的好,免得数错长度;第四种可以看到,在只定义局部变量的时候,如果不初始化,两种平台根本都不会调用汇编代码来干些什么。所以,从效率角度考虑,能不初始化就不初始化,如果要初始化,尽量在定义的时候初始化。字符串存储的时候,尽量使用4的整数倍长度,哪怕多写一两个\0,可以减少汇编指令的个数,长度11的时候,用了4*2+2+1这样来存储字符串,如果多写一个\0,就可以减少一条汇编指令了。没在64位机上验证,不过应该可以一条汇编指令存储8个字节的字符吧。

对比两个平台的汇编代码来看,vc编译的汇编代码注释要详细一些。但是vc平台的对应第二、三种初始化的操作,先把临时变量存在eax里,然后存在字符串变量里;而gcc中,直接从ebp里取,存在对应的内存里,每一次存储少一条指令。

 

 

你可能感兴趣的:(初始化)