1、代码优化概述

(1)代码优化:分为时间优化、空间优化

(2)代码优化与程序可读性之间是相互矛盾的

(3)需要优化的代码对象:频繁使用的代码需要进行优化

例:清除从指针data开始的N个字节空间

void menclr(char *data, int N)

{

        for(;N > 0; N--)

        {

                *data = 0;

                data ++;

        }

}

问题:(1)编译器是不知道N是否为0的

                (2)如果处理器是32位处理器,编译器不知道data是否是4字节对齐的,

                (3)编译器是不知道N是否是4的倍数的

结论:(1)编译器必须是保守的:①必须假定N的所有可能值②必须假定data所有可能的边界值

                (2)了解哪些方面编译器是保守的。

                (3)编写高效C代码,要求了解编译器对应的处理器体系结构

2、高效的C程序设计的途径

        通过研究编译器如何把C语言代码转换成ARM汇编代码,以帮助程序员区分快速和慢速的C语言代码,进而指导程序员进行更好的C程序设计。

3、优化方式:选择正确的变量数据类型

(1)变量的数据类型

①建议采用32位ARM机器

②Load/Store不同的C数据类型,效率会有所不同

(2)例:求校验和

int checksum_v1(int *data)

{

        char i;

        int sum = 0;

        for(i = 0; i < 64; i ++)

                sum += data[i];

        return sum;

}

i声明为char类型的优缺点是什么?

①chra类型的值表示范围超过了64,可以完成题目的要求

②char更节省寄存器和内存空间

上述代码对应的汇编代码为:

checksum_v1_s

        MOV r2,r0                ;r2=data,地址指针

        MOV r0,#0                ;sum = 0

        MOV r1,#0                ;  i = 0,计数器

checksum_v1_loop

        LDR r3,[r2,r1,LSL #2]        ;r3 = data[i]

        ADD r1,r1,#1                        ;r1 = i + 1

        AND r1,r1,#0xff                        ;i = (char)r1

        CMP r1,#0x40                        ;compare i,64

        ADD r0,r3,r0                                ;sum += r3

        BCC checksum_v1_loop                ;if(i < 64) loop

        MOV pc,r14                                      ;return sum

讨论:i是char类型,超过255要归零,所以汇编程序中要确保其不超过255,上述程序的汇编代码共10条指令。

(3)更改求校验和程序为:

int checksum_v2(int *data)

{

        unsigned int i;

        int sum = 0;

        for(i = 0; i < 64; i ++)

                sum += data[i];

        return sum;

}

上述程序的汇编代码为:

checksum_v2_s

        MOV r2,r0                ;r2=data,地址指针

        MOV r0,#0                ;sum = 0

        MOV r1,#0                ;  i = 0,计数器

checksum_v2_loop

        LDR r3,[r2,r1,LSL #2]        ;r3 = data[i]

        ADD r1,r1,#1                        ;r1++

        CMP r1,#0x40                        ;compare i,64

        ADD r0,r3,r0                                ;sum += r3

        BCC checksum_v2_loop                ;if(i < 64) loop

        MOV pc,r14                                      ;return sum

上述汇编代码共9条指令,比使用char类型少了一条指令

(4)如果要求和的数据由32位更改为16位

short checksum_v3(short *data)

{

        unsigned int i;

        short sum = 0;

        for(i = 0; i < 64; i ++)

                sum += data[i];

        return sum;

}

上述程序的汇编代码为:

checksum_v3_s

        MOV r2,r0                ;r2=data,地址指针

        MOV r0,#0                ;sum = 0

        MOV r1,#0                ;  i = 0,计数器

checksum_v3_loop

       ADD r3,r2,r1,LSL #1               ;r3 = &data[i]

        LDRH r3,[r3,#0]                       ;r3=data[i]

        ADD r1,r1,#1                        ;r1++

        CMP r1,#0x40                        ;compare i,64

        ADD r0,r3,r0                                ;r0 = sum +  r3

        MOV r0,r0, LSL #16                       

        MOV r0,r0, ASR  #16                ;sum = (short)r0

        BCC checksum_v3_loop                ;if(i < 64) loop

        MOV pc,r14                                      ;return sum

共12条指令,比对int型数据进行求和时的汇编代码多出3条。

讨论:对16位数据求校验和:

①LDRH指令与LDR指令不同,不支持移位地址偏移,所以需要用一条指令来单独计算地址。

②两次移位对应short数据类型,16位数据在32位系统上运算,需要进行左移、右移来得到实际的16位数。

③用data指针操作数据,避开数组。

④可以先用Int类型计算求和,计算完成后再返回short类型数据。

代码可以优化,修改为:

short checksum_v4(short *data)

{

        unsigned int i;

        int sum = 0;

        for(i = 0; i < 64; i ++)

                sum += *data++;

        return (short)sum;

}

上述程序的汇编代码为:

checksum_v4_s

        MOV r2,#0                ;sum = 0

        MOV r1,#0                ;  i = 0,计数器

checksum_v4_loop

      LDRSH r3,[r0] #2               ;r3 = *(data++)

        ADD r1,r1,#1                        ;r1++

        CMP r1,#0x40                        ;compare i,64

        ADD r2,r3,r2                               ;sum +=  r3       

        BCC checksum_v4_loop                ;if(i < 64) loop

        MOV r0,r2, LSL #16                       

        MOV r0,r0, ASR  #16                ;r0 = (short)sum

        MOV pc,r14                                      ;return r0

总结:①采用整型类型,省去了多余的移位操作,移位操作移动到了循环外

        ②尽量使用int类型,仅使用char、short的溢出归零特性。