SN单片机c程序优化方法

SONIX单片机C语言程序优化方法,对其他类型的单片机应该也会有一些借鉴作用
资料来源:SONIX单片机C语言编译器《SN8 C studio》里的帮助文档

1、如果在定义或声明变量为int数据类型时足够,请勿使用关键字“long”。 以同样的方式,如果浮动的精度足够,不要使用“double”。
2、如果声明一个通用指针,当程序中使用指针时,需要对指针指向RAM或ROM进行判断。 但是使用ram / rom指针可以避免这个额外的动作!

int* pInt;
int g;
void main()
{
    pInt = &g1;
    g = 1;
    if(*pInt != 1)
    return 1;
    return 0;
}
Rom has used : 93 [0x5D] words


----------


__RAM int* pRam;
int g;
int main()
{
    pRam = &g;
    g = 1;
    if(*pRam != 1)
    return 1;
    return 0;
}
Rom has used : 79 [0x4F] words

3、如果一个标志只有两个状态:0或1,可以采用位数据类型而不是int类型。 因为位类型的操作比int类型更简单,所以会产生较少的指令。 此外,位变量占用的内存比int变量少。
4、因为操作多维数组是复杂的,所以C编译器必须生成大量的指令来实现多维数组操作。所以没事不要用多维数组。
5、通常,当使用int数据类型时,C编译器将生成一些处理否定条件的指令,但是对于数组,大多数这些指令是无用的。 所以用户可以使用unsigned类型来避免这个问题。

int a[10];
int main(void)
{ 
    int i;
    for(i = 0;i<=9;i++)
    a[i] = 1;
}
Rom has used : 73 [0x49] words
--------------------
int a[10];
int main(void)
{ 
    unsigned i;
    for(i = 0;i<=9;i++)
    a[i] = 1;
}
Rom has used :70 [0x46] words

6、如果全局变量位于ram bank 0中,则不需要生成额外的指令来更改RBANK寄存器。

#pragma rambank 1
int g_i, g_j,g_k;
int main(void)
{
    int i,j,k;
    i = 1;
    g_i = 1;
    j = 1;
    g_j = 1;
    k = 1;
    g_k = 1;
}
Rom has used : 69 [0x45] words
---------------------
#pragma rambank 0
int g_i, g_j,g_k;
int main(void)
{
    int i,j,k;
    i = 1;
    g_i = 1;
    j = 1;
    g_j = 1;
    k = 1;
    g_k = 1;
}
Rom has used : 64 [0x40] words

7、由于位数据类型的操作比指针简单,使用位参考类型而不是指针是减少代码大小的更好方法。

#include<sn8p2708a.h>
int main(void)
{
    if(FP4CON2 != FP4CON3)
    return 1;
    else 
    return 0;
}
Rom has used : 76 [0x4C] words
----------------------
#pragma data_address 0xae:2
sbit fpcon2;
#pragma data_address 0xae:3
sbit fpcon3;
int main(void)
{
    if(fpcon2 != fpcon3)
    return 1;
    else 
    return 0;
}
Rom has used : 62 [0x3E] words

8、因为位数据类型的操作比位字段更简单,所以使用位参考类型而不是位归档是减少代码大小的更好方法。也就是直接位定义,而不需要把位归类。

struct BitField
{
    unsigned int bit0:1;
    unsigned int bit1:1;
    unsigned int bit2:1;
    unsigned int bit3:1;
    unsigned int bit4:1;
    unsigned int bit5:1;
    unsigned int :2;
};
int main(void)
{
    struct BitField bitfield;
    bitfield.bit0 = 1;
    if(bitfield.bit1==1)
    bitfield.bit2 = 0;
    if(bitfield.bit3!=0)
    bitfield.bit3 = 0;
}
Rom has used : 73 [0x49] words 
------------------------
int bitfield;
int main(void)
{
    sbit bit0 = bitfield:0;
    sbit bit1 = bitfield:1;
    sbit bit2 = bitfield:2;
    sbit bit3 = bitfield:3;
    bit0 = 1;
    if(bit1==1)
    {
        bit2 = 0;
    }
    if(bit3!=0)
    {
        bit3 = 0;
    }
}
Rom has used : 64 [0x40] words

9、为了实现相同的功能,使用变量会产生比指针少的指令。 所以不要尽可能使用指针。

int main (void)
{ 
    int i; 
    int *p = &i;
    *p= 1;
}
Rom has used : 62 [0x3E] words
--------------------------
int main (void)
{ 
    int i; 
    int *p = &i;
    i = 1;
}
Rom has used : 58 [0x3A] words

10、如果在程序中多次使用指针,其值不会频繁更改,则可以使用变量作为替代来完成相同的工作。

#include<sn8p2708a.h>
int main(void)
{
    int temp = R;
    int i = 2;
    int j = temp*i;
    int k = temp*j;
}
Rom has used : 71 [0x47] words
-----------------------
#include<sn8p2708a.h>
int main(void)
{
    int i = 2;
    int j = R*i;
    int k = R*j;
}
Rom has used : 69 [0x45] words

11、当使用“++ / - ”和其他运算符在一起时,首先编译器将变量的值增加到寄存器之前或之后,然后获取寄存器的值开始其他操作,因此大量的冗余代码 将被生成,所以最好只使用“++ / - ”!

#include<sn8p2708a.h>
int main(void)
{ 
    long i;
    if(++i == 10) 
    i = 0;
}
Rom has used : 74 [0x4A] words
---------------------------
#include<sn8p2708a.h>
int main(void)
{ 
    long i;
    i++;
    if(i == 10)
    i = 0;
}
Rom has used : 64 [0x40] words

12、有一个关于每个类型的乘法代码大小的序列:unsigned <int <long <float.So对于代码大小的考虑,用户将选择数据类型的最小大小来声明变量。这里就不举例了。


13、有一个关于每个类型的除法的代码大小的序列: unsigned <= int(char)<long <float .So为代码大小的考虑,用户将选择最小的数据类型大小来声明变量。乘法和除法还是有点区别的。
14、在某些时候,如果将int和float数据类型的乘法结果分配给一个int变量,为了避免加载Std库并获得相同的结果,有一个消费建议将float数据类型转换为int。

int main(void)
{
    int i1 = 12;
    int i2 =i1 * 2.0;
}
Rom has used :472 [0x1D8] words
-------------------------------------
int main(void)
{
    int i1 = 12;
    int i2 =i1 * 2;
}
Rom has used : 56 [0x38] words

15、有时候,如果将int和float数据类型的除法结果分配给int变量,为避免加载Std库并获得相同的结果,尽可能的将float数据类型转换为int。

int main(void)
{
    int i1 = 12;
    int i2 =i1 /3.0;
}
Rom has used : 472 [0x1D8] words
--------------------------
int main(void)
{
    int i1 = 12;
    int i2 =i1/ 3;
} 
Rom has used : 56 [0x38] words

16、将int ant float类型转换为尽可能与int类型相关的除法,因为实现int和float的乘法比int类型的分割更复杂! 例如:

int main(void)
{ 
    int i= 2;
    int j = i*0.5;
} 
Rom has used : 461 [0x1CD] words
----------------------
int main(void)
{ 
    int i= 2;
    int j = i/2;
}
Rom has used : 120 [0x78] words

17、通常,乘法的代码大小小于相同数据类型的除法,因此尽可能地将分割转换为乘法。

int main(void)
{ 
    float i= 2.0;
    float j = i/2.0;
}
Rom has used : 418 [0x1A2] words
----------------------------
int main(void)
{ 
    float i= 2.0;
    float j = i*0.5;
}
Rom has used : 387 [0x183] words

18、如果赋给int变量赋值的结果,并且涉及浮点类型的加法。有一个很好的建议将float类型转换为int,因为这里使用float类型在大多数时候是无用的!

int main(void)
{
    int i1 = 12;
    int i2 =i1 + 2.0;
}
Rom has used : 472 [0x1D8] words
------------------------------
int main(void)
{
    int i1 = 12;
    int i2 =i1 + 2;
}
Rom has used : 56 [0x38] words

19、如果将减法的结果分配给int变量,并且涉及浮点型的相加。 有一个很好的建议来将float类型隐藏为int,因为在这里使用float类型在大多数时候是无用的!

int main(void)
{
    int i1 = 12;
    int i2 =i1 – 3.0;
}
Rom has used : 74 [0x4A] words
----------------------------------
int main(void)
{
    int i1 = 12;
    int i2 =i1 - 3;
}
Rom has used : 71 [0x47] words

20、一般来说,“<<”的操作比“*”简单,所以采取“<<”而不是“*”是减少代码大小的好主意。

int main(void)
{
    long i = 2;
    i = i * 64;
}
Rom has used : 82 [0x52] words
----------------------------------
int main(void)
{
    long i = 2;
    i = i << 6;
}
Rom has used : 62 [0x3E] words

21、一般来说,“>>”的操作比“/”简单,所以取代“/”代替“>>”是减少代码大小的好主意。

int main(void)
{
    long i = 264;
    i = i/64;
}
Rom has used : 183 [0xB7] words
--------------------------
int main(void)
{
    int i = 264;
    i = i>>6;
}
Rom has used : 65 [0x41] words

22、一般来说,“&”的操作比“%”简单,所以采用“&”代替“%”是减少代码大小的好主意。

int main(void)
{
    int i = 6;
    int j = i%8;
}
Rom has used : 120 [0x78] words
--------------------------------
int main(void)
{
    int i = 6;
    int j1 = i&7;
}
Rom has used : 56 [0x38] words

23、如果芯片不支持MUL指令,则C编译器将加载Std库以完成此工作。 为了避免这种复杂的操作,它是尽可能地使用加法而不是简单乘法的更好的方法。

int main(void)
{
    int i, j;
    i = i * 3;
}
Rom has used : 82 [0x52] words
--------------------------
int main(void)
{
    int i, j;
    i = i + i + i ;
}
Rom has used : 59 [0x3B] words

24、如果compare的操作在integer和const之间,对于代码大小的考虑,可以将const更改为const +1,并使用“> =”而不是“>”。

int main(void)
{
    int i1 = 12;
    int i2 = 0;
    if(i1 > 10)
    i2 = 1;
}
Rom has used : 63 [0x3F] words
------------------------------
int main(void)
{
    int i1 = 12;
    int i2 = 0;
    if(i1 >= 11)
    i2 = 1;
}
Rom has used : 61 [0x3D] words

25、如果compare的操作在integer和const之间,对于代码大小的考虑,可以将const更改为const + 1并使用“<”而不是“<=”。

int main(void)
{
    int i1 = 12;
    int i2 = 0;
    if(i1 <= 10)
    i2 = 1;
}
Rom has used : 66 [0x42] words
------------------------------
int main(void)
{
    int i1 = 12;
    int i2 = 0;
    if(i1 < 11)
    i2 = 1;
}
Rom has used : 61 [0x3D] words

26、对于位变量,“〜”的操作比“!”简单,所以取“〜”而不是“!” 是减少代码大小的好主意。

int main(void)
{
    bit i,j;
    i = 0;
    j = !i;
    if(j == 0)
    return 1;
    return 0;
}
Rom has used : 82 [0x52] words
--------------------------------
int main(void)
{
    bit i,j;
    i = 0;
    j = ~i;
    if(j == 0)
    return 1;
    return 0;
}
Rom has used : 71 [0x47] words

27、对于长表达式,c编译器将生成一些临时变量来存储子表达式的值。 我们可以将复杂的操作分解成简单的语句序列。

int main(void)
{ 
    int a;
    int b;
    int c;
    int d, e;
    e = (a + b) * c * a + b;
}
Rom has used : 66 [0x42] words
---------------------------
int main(void)
{ 
    int a, b, c, d, e; 
    e = a + b;
    e *= c;
    e *= a;
    e += b;
}
Rom has used : 60 [0x3C] words

28、对于复杂的if语句,c编译器将生成一些临时变量来存储一些子条件的值。 我们可以将复杂的操作分解成简单的语句序列。

int main(void)
{
    int a,b,c;
    if(a == b && b == c && a != c )
    ;
}
Rom has used : 70 [0x46] words
------------------------------
int main(void)
{
    int a,b,c;
    if(a==b)
    if(b == c)
    if(a != c)
    ;
}
Rom has used : 64 [0x40] words

29、有时候,调整框架的“if”语句可以减少代码大小,例如:

#include<sn8p2708a.h>
int main(void)
{
    int i,j;
    int flag;
    if(flag)
    i = 0;
    else
    i = 1;
}
Rom has used : 59 [0x3B] words
--------------------------------
#include<sn8p2708a.h>
int main(void)
{
    int i, j;
    int flag;
    i = 1;
    if (flag)
    i = 0;
}
Rom has used : 58 [0x3A] words

30、对于c源代码,编译器的条件表达式的语法树比“if else”语句更复杂,因此编译器可以比“if else”语句的条件表达式生成更少的指令来实现该函数。

#include<sn8p2708a.h>
int main(void)
{ 
    int i;
    i = FP27M ? 1:0;
}
Rom has used : 60 [0x3C] words
------------------------------------
#include<sn8p2708a.h>
int main(void)
{ 
    int i;
    if(FP27M) i = 1;
    else i = 0;
}
Rom has used : 58 [0x3A] words

31、编译器可以根据条件编译选择正确的语句,因此是减少代码大小的好方法。

int LETTER = 1; 
void main() 
{ 
    char str[20]="C Language";
    char c; 
    int i=0; 
    while(i<=19)
    { 
        c = str[i];
        if (LETTER == 1)
        if(c>='a'&& c<='z') c=c-32; 
        else 
        if(c>='A'&& c<='Z') c=c+32; 
        str[i] = c;
        i++; 
    } 
}
Rom has used : 144 [0x90] words
-------------------------------------------------
#define LETTER 1 
void main() 
{ 
    char str[20]="C Language";
    char c; 
    int i=0; 
    while(i<=19)
    { 
        c = str[i];
        #if LETTER 
        if(c>='a'&& c<='z') c=c-32; 
        #else 
        if(c>='A'&& c<='Z') c=c+32; 
        #endif 
        str[i] = c;
        i++; 
    } 
}
Rom has used : 124 [0x7C] words

32、当程序中使用多层“if else”语句时,建议使用“switch”语句而不是多层。 如果“switch”语句满足跳转表的条件,则编译器将为此生成较少的指令。

int main(void) 
{ 
    int i, test = 1;
    if(test == 0) i = 0;
    else if (test == 1) 
        i = 1;
    else if (test == 2) 
        i = 2;
    else if (test == 3) 
        i = 3;
    else if (test == 4) 
        i = 4;
    else if (test == 5) 
        i = 5;
    else if(test == 6)
        i = 6;
    else if(test ==7)
        i = 7;
    else if(test == 8) 
        i = 8;
}
Rom has used : 106 [0x6A] words
---------------------
int main(void)
{ 
int i; int test = 1;
switch (test) {
    case 0: i = 0;
    break;
    case 1: i = 1;
    break;
    case 2: i = 2; 
    break;
    case 3: i = 3; 
    break;
    case 4: i = 4; 
    break;
    case 5: i = 5; 
    break;
    case 6: i = 6;
    break;
    case 7: i = 7; 
    break;
    case 8: i = 8; 
    break; }
}
Rom has used : 102 [0x66] words

33、如果“switch”语句不符合跳转表的条件,则编译器会生成比if else语句更多的指令。

void main( )
{
    int i = 1;
    switch (i){
        case 1: i=1;
        break;
        case 25: i=2; 
        break;
        case 43: i=3;
        break;
        case 102: i=4; 
        break;
        case -6: i=5; 
        break; }
}
Rom has used : 106 [0x6A] words
------------------------------
void main()
{
    int i = 1;
    if (i==1)
        i=1;
    else if (i==25)
        i=2;
    else if (i==43)
        i=3;
    else if (i==102)
        i=4;
    else if (i==-6)
        i=5;
}
Rom has used : 82 [0x52] words

34、避免在if / while / for中的函数调用,因为在“if / while / for”中的函数调用将生成隐式变量

int fun (void)
{
    int i = 0;
    return i;
}
int main (void)
{ 
    int i;
    if(fun() == 0)
        i = 0;
    else if (fun() == 1)
        i = 1;
    else if (fun() == 2)
        i = 2;
}
Rom has used : 75 [0x4B] words
------------------------
int fun(void)
{
    int i = 0;
    return i;
}
int main(void)
{ 
    int i, temp = fun();
    if (temp== 0)
        i = 0;
    else if (temp == 1)
        i = 1;
    else if (temp == 2)
        i = 2;
}
Rom has used : 73 [0x49] words

35、当在中断功能中调用其他函数时,编译器需要生成一组操作,以便在发生中断时保存和恢复环境。 所以直接在中断函数中编写代码,以避免编译器尽可能的做这个繁琐的工作!

void fun()
{
    __asm
    {
        MOV A, #0x01
        B0MOV RBANK, A;
    }
}
__interrupt interruptfun()
{
    fun();
}
void main(void)
{
}
Rom has used : 126 [0x7E] words
-------------------
__interrupt interruptfun()
{
__asm
    {
        MOV A,#0x01
        B0MOV RBANK A;
    }
}
void main (void)
{
}
Rom has used : 64 [0x40] words

36、如果在程序中频繁使用某些操作,则将它们收集到一个函数中是减少代码大小的一种可行的方法。

int array[10][10];
int main(void)
{
    int i,j;
    for(i = 0;i <= 9; i++)
        for(j = 0;j<= 9; j++)
            array[i][j] = 0;
    // do other something
}
int fun(void)
{
    int i,j;
    for(i = 0;i <= 9; i++)
        for(j = 0;j<= 9; j++)
            array[i][j] = 0;
    // do other something
}
Rom has used : 180 [0xB4] words
------------------------------
int array[10][10];
void init_array(void)
{
    int i, j;
    for(i = 0;i <= 9; i++)
        for(j = 0;j<= 9; j++)
            array[i][j] = 0;
}
int main(void)
{
    init_array();
    // do other something
}
int fun(void)
{
    init_array();
    // do other something
}
Rom has used : 129 [0x81] words

37、在函数中使用参数时,首先编译器必须将参数输入到参数中。 然后使用参数传递值,但是使用全局变量可以避免这个额外的动作来实现相同的功能

int fun(int g_i,int g_j)
{
    int i = g_i;
    int j = g_j;
}
int main(void)
{
    int i, j;
    fun(i, j);
}
Rom has used : 64 [0x40] words
--------------------------------
int g_i, g_j;
int fun (void)
{
    int i = g_i;
    int j = g_j;
}
int main(void)
{
    fun();
}
Rom has used : 60 [0x3C] words

38、传递类型为struct或union的参数的地址将节省更多的代码大小。 否则,它需要更多的代码大小为结构或联合的副本。

typedef struct Solstruct
{
    int i;
    int j;
    int k;
    int q;
}Sstruct;
void fun(struct Solstruct s)
{
}
int main(void)
{
    struct Solstruct s;
    fun(s);
}
Rom has used : 66 [0x42] words
-------------------------------
typedef struct Solstruct
{
    int i;
    int j;
    int k;
    int q;
}Sstruct;
void fun(struct Solstruct *s)
{
}
int main(void)
{
    struct Solstruct s;
    fun(&s);
}
Rom has used : 58 [0x3A] words

39、如果函数不需要返回值,请将其声明为void类型,因为如果函数不是void类型,那么编译器会生成一些有关返回值的代码

int fun(void)
{
    return 1;
}
int main(void)
{
    fun();
    return 0;
}
Rom has used : 56 [0x38] words
--------------------------------
void fun(void)
{
} 
int main(void)
{
    fun();
    return 0;
}
Rom has used : 54 [0x36] words

40、在程序中使用函数指针时,它比函数更复杂,所以不要尽可能使用它。

void (*funptr)();
void fun(void)
{
}
int main(void)
{
    funptr = fun;
    funptr();
}
Rom has used : 82 [0x52] words
-----------------------------
void (*funptr)();
void fun(void)
{
}
int main(void)
{
    funptr = fun;
    fun();
}
Rom has used : 58 [0x3A] words

41、例如,由编译器生成的关于多维数组的指令是复杂和冗余的,因此我们可以使用内联汇编器!

#include<sn8p2708a.h>
int a[5][5];
int main (void)
{ 
    int i, j;
    for(i=0;i<=4;i++)
    {
        for(j=0;j<=4;j++)
        {
            a[i][j] = 1;
        }
    }
}
Rom has used : 128 [0x80] words
-------------------------------
#include<sn8p2708a.h>
int a[5][5];
int main(void)
{ 
    int i,j;
    for(i=0;i<=4;i++)
    {
        for(j=0;j<=4;j++)
        {
            __asm{
            SelectBank(i)
            MOV A, #5
            MUL A,CNameToAsmLabel(i)
            SelectBank(j)
            ADD A,CNameToAsmLabel(j)
            ADD A, #(CNameToAsmLabel(a))$L
            B0MOV Z,A;
            MOV A, #(CNameToAsmLabel(a))$M
            B0MOV Y,A
            MOV A,#0x01
            B0MOV @YZ, A}
        }
    }
}
Rom has used : 81 [0x51] words

42、好的算术比一个好的编译器更有效!

void BubbleSort(int* pData,int Count)
{
    int iTemp;
    int i,j;
    for(i=1;i<Count;i++)
    {
        for(j=Count-1;j>=i;j--)
        {
            if(pData[j]<pData[j-1])
            {
                iTemp = pData[j-1];
                pData[j-1] = pData[j];
                pData[j] = iTemp;
            }
        }
    }
}
void main()
{
    int data[] = {10,9,8,7,6,5,4};
    BubbleSort(data,7);
}
Rom has used : 272 [0x110] words
---------------------------
void InsertSort(int* pData,int Count)
{
    int iTemp;
    int iPos;
    int i;
    for(i=1;i<Count;i++)
    {
        iTemp = pData[i];
        iPos = i-1;
        while((iPos>=0) && (iTemp<pData[iPos]))
        {
            pData[iPos+1] = pData[iPos];
            iPos--;
        }
        pData[iPos+1] = iTemp;
    }
}
void main()
{
    int data[] = {10,9,8,7,6,5,4};
    InsertSort(data,7);
}
Rom has used : 241 [0xF1] words

版权声明:本文为LHChandsome原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。