C/C++的内嵌汇编

来源:互联网 发布:网络约租车管理办法 编辑:程序博客网 时间:2024/05/17 00:10
这样的一个两层循环,本来觉得没什么不妥,这是算法书的例子代码
C/C++ code
?
1
2
3
for(i=0; i<256; i++)
    for(k=0; k<b[i]; k++)
        array[j++] = i;



但VS2008直接给优化成了下面的,快了20%左右
C/C++ code
?
1
2
3
4
5
for(i=0; i<256; i++)
{
    memset(array+j,i,b[i]);
    j += b[i];
}


以前我总说教“大部分的程序员写汇编是写不过C编译器的优化的”,今天想自己挑战挑战
以前没学过32位汇编,于是就选了比较简单的鸽巢排序算法

原先的C版,排序1000万个字节(鸽巢排序最是和排序字节),耗时0.013s(release),0.060s(debug)
C/C++ code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
//这是已根据优化的结果作了修改,release速度没变,exe体积小了些
void PigeonholeSort(BYTE *array, int length)
{
    int b[256] = {0};
    int i,j = 0;
    for(i=0; i<length; i++)
        b[array[i]]++;
    for(i=0; i<256; i++)
    {
        memset(array+j,i,b[i]);
        j += b[i];
    }
}

先按照算法书上C的逻辑(不是上面那个)写了一遍,0.023s,比debug快,比release慢,意料之内,因为debug版不仅没有任何优化,还有用于调试的附加代码

有一处为了传一个字节我用了八位寄存器al,发现比较慢,换扩展移动movzx,这样寄存器就能使用eax了,速度提高到0.018s

发现没有像上面那样的低级错误了,的确找不到不改变逻辑就提升效率的方法了

反汇编原来的C版,晕,原来做了本文开头的优化

按照反汇编的逻辑修改,比C优化的结果又少了个把条指令,速度也赶上了C版,0.013s

汇编最终版本,包括测试代码,masm32最大的好处就是能把汇编写的和C语言几乎一样,所以我这个基本不会win32汇编的菜鸟能写,高精度计时函数由于有64位减法、乘法、除法和求模运算,本菜鸟还不会写,就直接用C封装给汇编调用了

PS:masm貌似并不很流行,可能是他写汇编确实开发效率搞,单像下面这种C风格的汇编,还能用C语言标准库……又有什么意思呢,只有PigeonholeSort算法部分才有点汇编的影子,测试代码就是C嘛

也就是玩玩而已,同时告诉大家C的效率是绝对够用了
Assembly code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
.386
.model flat,stdcall
option casemap:none
include    windows.inc
include       kernel32.inc
include    advapi32.inc
include    msvcrt.inc
includelib kernel32.lib
includelib advapi32.lib
includelib user32.lib
includelib msvcrt.lib
includelib TimeCalc.lib
 
 
HCRYPTPROV     TYPEDEF    DWORD
 
TimeStart proto
 
TimeDisplay proto
 
.const
PROV_RSA_FULL  equ        00000001h
szInfo1        db         '请输入排序长度:',0
szInfo2        db         '请输入数字!',0ah,0
szInfo3        db         '请输入保存位置:',0
szInfo4        db         '结果已保存在:  %s',0ah,0
szInfo5        db         '%u',0
szInfo6        db         'wb',0
.code
 
PigeonholeSort proc array:DWORD,len:DWORD
    LOCAL b[256]:DWORD
    invoke crt_memset,addr b,0,sizeof b
    mov    edi,array
    mov    ebx,0
    .while ebx < len
        movzx  eax,byte ptr[edi+ebx]
        inc    dword ptr[esp+eax*4]
        inc    ebx
    .endw
         
    mov    esi,0
    mov    edx,0
    mov    eax,edi
    .while esi < 256
        mov    ebx,dword ptr [esp+esi*4]
        invoke crt_memset,eax,esi,ebx
        add    eax,ebx
        inc    esi
    .endw
    ret
PigeonholeSort endp
 
 
main proc
        LOCAL crypt_prov_:DWORD
        LOCAL resulttime:QWORD
        LOCAL array:DWORD
        LOCAL top:DWORD
        LOCAL hFile:DWORD
        LOCAL filename[MAX_PATH]:BYTE
        LOCAL tmpbuf[MAX_PATH]:BYTE
    mov top,0
    mov crypt_prov_,0
    invoke crt_memset ,addr tmpbuf,0,MAX_PATH
    invoke CryptAcquireContext,addr crypt_prov_,NULL,NULL,PROV_RSA_FULL,0
     
    .repeat
        invoke crt_printf,addr szInfo1
        invoke crt_scanf,addr szInfo5,addr top
        mov    hFile,eax
        invoke crt_gets,addr tmpbuf
        .if    hFile <= 0
            invoke crt_printf,addr szInfo2
            .continue
        .endif
        .break
    .until  0
     
    invoke crt_malloc,top
    mov    array,eax
    invoke CryptGenRandom,crypt_prov_,top,array
    invoke CryptReleaseContext,crypt_prov_,0
     
    invoke crt_printf,addr szInfo3
    invoke crt_gets,addr filename
    invoke crt_fopen,addr filename,addr szInfo6
    mov    hFile,eax
     
    call   TimeStart
     
    invoke PigeonholeSort,array,top
     
    call   TimeDisplay
     
    .if    hFile != NULL
        invoke crt_fwrite,array,1,top,hFile
        invoke crt_fclose,hFile
        invoke crt_printf,addr szInfo4,addr filename
    .endif
     
    invoke crt_free,array
    ret
 
main endp
 
start:
        call   main
        ret
end     start