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