zoukankan      html  css  js  c++  java
  • 从汇编看待变量初始化

    变量如何初始化,才能更有效率?通过查看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]='';
    }
    
    void main()
    {
    	funA();
    	funB();
    	funC();
    	funD();
    }


    1、VC编译:vc生成汇编代码: cl /FA varInit.c

    	TITLE	D:5testVarInitvarInit.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:5testVarInitvarInit.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"
    	.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的整数倍长度,哪怕多写一两个,可以减少汇编指令的个数,长度11的时候,用了4*2+2+1这样来存储字符串,如果多写一个,就可以减少一条汇编指令了。没在64位机上验证,不过应该可以一条汇编指令存储8个字节的字符吧。

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

  • 相关阅读:
    日记 2018/1/12
    【程序员笔试面试必会——排序①】Python实现 冒泡排序、选择排序、插入排序、归并排序、快速排序、堆排序、希尔排序
    Python笔试、面试 【必看】
    高性能Go并发
    Go连接MySql数据库Error 1040: Too many connections错误解决
    MAC 配置文件 ~/.zshrc
    go-statsd项目
    日记 2017.11.20
    sed 命令详解
    Opentsdb简介(一)
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3190005.html
Copyright © 2011-2022 走看看