
HEW中有效的编程技术
有效的编程技术
1. 为增进 ROM 的效率和执行速度,可用 1 字节大小来代表的数据,应被声明为字符 / 无符号字符 (char/unsigned char) 类型。
2. 为增进目标的效率和执行速度,任何具有正数值的变量应被声明为无符号。
3. 禁止冗余类型 转换
、 通过 确保 在相同大小的数据项目之间执行操作,可增进 ROM 的效率和执行速度。
4. 使用
const 限 定符 、 保持 值不变的 初 始化数据应被列为常数以节 省 RAM 区域 。
已初 始化的数据项目经常可能在值上变更。 这些数据项目于连接期间在 ROM 上 分配 ,并在程序执行 开 始时被复 制 到 RAM , 导致 它 们 同时在 ROM 和 RAM 区域内 被 分配 。 在程序执行的过程中 保持 值不变的数据项目可被列为常数,以使它 们只 在 ROM 区域内 被 分配 。
Eg: unsigned char a[5]={1, 2, 3, 4, 5};
const unsigned char a[5]={1, 2, 3, 4, 5}; // 优化后
在优化前,除了 ROM 以外,程序 还 需要在 RAM 为 分配 目标大小表中所列 出 的数据 区域 大小。
5. 使用一 致 的变量大小,在 循环 语句中作 比较 时,可使用 统 一的变量大小来 消 除对扩展代码的需要,并缩减所产生的代码大小。
6 . 将
in-file 函数指定为 静态 函数, 只 在一个 文 件中使用的函数应被指定为 静态
(static) 。指定为 静态 的函数若不被外 部 函数所 调 用,则将被 删 除。 当 为 内联 扩展指定时,这些函数 也 将被 删 除,以增进大小效率。
7 . 统 一 公 用表达式
, 通过在 多 个 算 术表达式中 统 一 公 用 组 件,可增进 ROM 的效率和执行速度。
Eg: (优化前的 C 语言程序)
unsigned char a,b,w,x,y,z;
void func(void)
{
a=x+y+z;
b=x+y+w;
}
(优化后的 C 语言程序)
unsigned char a,b,w,x,y,z;
void func(void)
{
unsigned char tmp;
tmp=x+y;
a=tmp+z;
b=tmp+w;
}
8. 增进条件决定 , 通过 评估 一 次 操作中的相似条件表达式来增进 ROM 的效率。
(优化前的 C 语言程序)
unsigned char a,b;
unsigned char func(void)
{
if (!a) return(0);
if (a&&!b) return(0);
return(1);
}
(优化后的 C 语言程序)
unsigned char a,b;
unsigned char func(void)
{
if (a&&b) return(1);
else return(0);
}
9. 使用 替换 值的条件决定
当 在条件表达式中对决定语句使用 替换 值时,可通过将 赋 值语句 视 为条件决定语句来增进 ROM 的效率。
(优化前的 C 语言程序)
char *s,*d;
void func(void)
{
while(*s){
*d++ = *s++;
}
*d++ = *s++;
}
(优化后的 C 语言程序)
char *s,*d;
void func(void)
{
while(*d++ = *s++);
}
10. 使用 合适 的运 算 法
如 果 算 术表达式 包含 常用术语,应将这些术语 析出 以缩减执行 算 术操作的 次 数。 这可同时增进 ROM 的效率和执行速度。
解 决 三阶 方程式。
(优化前的 C 语言程序)
unsigned char a,b,c,d,x,y;
void func(void)
{
y=a*x*x*x+b*x*x+c*x+d;
}
(优化后的 C 语言程序)
unsigned char a,b,c,d,x,y;
void func(void)
{
y=x*(x*(a*x+b)+c)+d;
}
11. 使用 公 式
使用数 学公 式以缩减 面向算 法的编码技术中所需的 算 术操作 次 数。 这可同时增进 ROM 的效率和执行速度。
计 算 1 到 100 的 总 和。
(优化前的 C 语言程序)
unsigned int s;
unsigned int n=100;
void func(void)
{
unsigned int i;
for (s=0,i=1;i<=n;i++)
s+=i;
}
(优化后的 C 语言程序)
unsigned int s;
unsigned int n=100;
void func(void)
{
s=n*(n+1)>>1;
}
12. 使用本 地 变量
通过将可用作本 地 变量的 临 时变量 、循环 计数 器等 声明为本 地 变量,可增进 ROM 的效率和执行速度。
同 样地 ,在对本 地 变量执行操作前,可通过将 多 个 算 术表达式的普遍外 部 变量 分配给 本 地 变量来提高效率。
将变量
a 增 加 到变量
b、
c 和
d ;将结果存储在变量
b、
c 和
d 内 。
(优化前的 C 语言程序)
unsigned char a,b,c,d;
void func(void)
{
b+=a;
c+=a;
d+=a;
}
(优化后的 C 语言程序)
unsigned char a,b,c,d;
void func(void)
{
unsigned char wk;
wk=a;
b+=wk;
c+=wk;
d+=wk;
}
13. 将
f 分配给浮 点类型常数
在 浮 点 算 术操作 涉 及 包含 在 浮 点类型的可 分配 值 范围内 ( 7.0064923216240862e-46f 到 3.4028235677973364e+38f )的常数的 情形 下,在数字值之 后分配 字 母“ f ” 以 消 除可能 转换 为 复式
(double) 类型的冗余类型 转换 。
(优化前的 C 语言程序)
float a,b;
void func(void)
{
a=b+1.0;
}
(优化后的 C 语言程序)
float a,b;
void func(void)
{
a=b+1.0f;
}
14. 指定 移位 操作中的常数
对于 移位 操作, 如 果 移位 计数是一个变量,编译程序将会 调 用运行时例程以处理操作。 如 果 移位 计数是一个常数,编译程序将不会 调 用可有效增进执行速度的运行时例程。
(优化前的 C 语言程序)
int data;
int sht=8;
void func(void)
{
data=data<<sht;
}
(优化后的 C 语言程序)
#define SHT 8
int data;
void func(void)
{
data=data<<SHT;
}
15. 使用 移位 操作
在进行 乘 法和 加 法运 算 时, 尽 可能使用 移位 操作。
(优化前的 C 语言程序)
int data,a;
void main()
{
a=data+data+data;
}
(优化后的 C 语言程序)
int data,a;
void main()
{
a=(data<<1)+data;
}
16. 统 一连 续
ADD 指令
在 遇 到连 续加 法代码时,编译程序将执行一 致 的优化。 要 充分利 用此优化,必须 尽 可能 地 将 加 法运 算 连 续 编码。
(优化前的 C 语言程序)
int a,b;
void main()
{
a+=10;
b=10;
a+=20;
}
(优化后的 C 语言程序)
int a,b;
void main()
{
b=10;
a+=10;
a+=20;
}
17. 循环 处理
通过使用减量计数 器 及将终止条件和零相 比 ,可增进 ROM 的效率和执行速度。
(优化前的 C 语言程序)
unsigned char a[10],b[10];
int i;
void func(void)
{
for(i=0; i<10; i++)
b[i]=a[i];
}
(优化后的 C 语言程序)
unsigned char a[10],b[10];
int i;
void func(void)
{
for(i=9; i>=0; i--)
b[i]=a[i];
}
18. 选 择 重复 控制 语句
如 果 循环 语句被执行 至少 一 次 ,应 该 使用
do-while 语句来将它编码以缩减 循环 计数决定的一 次 操作, 从 而增进 ROM 的效率和执行速度。
(优化前的 C 语言程序)
unsigned char a[10],len=10;
unsigned char p1[10],p2[10];
void func(void)
{
char i;
for (i=len; i>0; i--)
p1[i-1]=p2[i-1];
}
(优化后的 C 语言程序)
unsigned char a[10],len=10;
unsigned char p1[10],p2[10];
void func(void)
{
char i=len;
do{
p1[i-1]=p2[i-1];
} while(--i);
}
19. 将不变量表达式 从循环 的 内部移 到外 部
如 果 出现 在 循环内部 的不 等 在 循环 外 部 被定 义 ,不 等只 在 循环 的 开头 被 评估 ,这将缩减在 循环 中执行的指令数目。 结果执行速度 获 得增进
(优化前的 C 语言程序)
unsigned char a[10],b,c;
int i;
void func(void)
{
for (i=9; i>=0; i--)
a[i]=b+c;
}
(优化后的 C 语言程序)
unsigned char a[10],b,c;
int i;
void func(void)
{
unsigned char tmp;
tmp=b+c;
for (i=9; i>=0; i--)
a[i]=tmp;
}
20. 合 并 循环 条件
在 循环 条件相同 或 相似的 情形 下,可通过将它 们合 并来增进 ROM 的效率和执行速度。
(优化前的 C 语言程序)
int a[10],b[10];
void f(void)
{
int i,j;
for (i=0; i<10; i++)
a[i]=0;
for (j=0; j<10; j++)
b[j]=1;
}
(优化后的 C 语言程序)
int a[10],b[10];
void f(void)
{
int i;
for (i=0; i<10; i++){
a[i]=0;
b[i]=1;
}
}
21. 使用指 针 变量
如 相同变量(外 部 变量)被 屡次参 考 或 必须存取数 组元素 , ROM 的效率和执行速度可通过使用指 针 变量来增进。
使用指 针 变量会生成 采 用有效率的 寻址 模式( @Rn 、 @Rn+ 、 @-Rn )的代码。
实例
将数 组
data2 的 元素 复 制 到数 组
data1 。
(优化前的 C 语言程序)
void func(int data1[],int data2[])
{
int i;
for (i=0; i<10; i++)
data1[i]=data2[i];
}
(优化后的 C 语言程序)
void func(int *data1,int *data2)
{
int i;
for (i=0; i<10; i++){
*data1=*data2;
data1++; data2++;
}
}
22. 确保 数据 兼容 性
数据项目以所声明的 顺 序 分配 。 通过有效指定数据项目声明的 顺 序以 消 除 虚 设存储 区 的生成,可增进使用 ROM 和 RAM 的效率。
实例
分配总 数 8 字节的数据。
(优化前的 C 语言程序)
char a;
long b;
char c;
short d;
(优化后的 C 语言程序)
char a;
char c;
long b;
short d;
23. 数据 初 始化的技术
要缩减程序大小,任何需要 初 始化的变量必须在声明时被 初 始化。
24. 统 一数 组元素 的 初 始化
在一些数 组元素 必须被 初 始化的 情况 下,通过将它 们分组 到结 构 以使它 们 可以在 单 一操作中被 初 始化,将可增进 ROM 的效率。
使用相应值对化数 组
a 、
b 和
c 进行 初 始化。
(优化前的 C 语言程序)
void f(void)
{
unsigned char a[]={0,1,2,3};
unsigned char b[]="abcdefg";
unsigned char c[]="ABCDEFG";
}
(优化后的 C 语言程序)
void f(void)
{
struct x{
unsigned char a[4];
unsigned char b[8];
unsigned char c[7];
} A
={0,1,2,3,"abcdefg","ABCDEFG"};
}
25. 将 参 数 传递 为结 构地址
未 被 分配 到 寄 存 器 的 参 数必须使用结 构 的 地址 来 传递 以缩减程序大小。
在需要大的 参 数和使用大量 参 数的 情况 下,必须在将 参 数 传递 到目标函数之前,将它 们 在结 构 中 分组 以缩减程序大小。 如 果 参 数被声明为结 构 的成 员 ,且结 构 的 起 始 地址 被 当 作 参 数 传递 到目标函数,接 收 函数将可 依 据接 收地址 来存取成 员 。
实例
将 长 类型数据
a 、
b 、
c 和
d 传递 到函数
func 。
(优化前的 C 语言程序)
void sub(long,long,long,long);
long a,b,c,d;
void func(void)
{
sub(a,b,c,d);
}
(优化后的 C 语言程序)
void sub(struct ctag *);
struct ctag{
long a;
long b;
long c;
long d;
}x;
void func(void)
{
sub(&x);
}
26. 将结 构分配给寄 存 器
在本 地 变量被 当 作结 构 使用时,必须声明成 员 以便可以将变量 直 接 分配 到 寄 存 器 。
实例
将结 构 数据 传递 到函数
func 。
(优化前的 C 语言程序)
struct ST {
char a;
short b;
char c;
}pst;
void main()
{
struct ST s;
s.a=pst.a+10;
s.b=s.a+s.c;
func(s);
}
(优化后的 C 语言程序)
struct ST {
short b;
char a;
char c;
}pst;
void main()
{
struct ST s;
s.a=pst.a+10;
s.b=s.a+s.c;
func(s);
}
27. 增进函数被定 义 的程序 位置
通过在同一 文 件中定 义 任何经常在模 块 中 调 用的函数,可能可以增进 ROM 的效率和执行速度。
实例
从 函数
func 和
func1 调 用函数
func2 。
(优化前的 C 语言程序)
extern int func2(void);
int ret;
void func(void)
{
int i;
i=func2();
ret = i;
}
void func1(void)
{
int i;
i=func2();
ret = i;
}
(优化后的 C 语言程序)
int ret;
int func2(void)
{
return 0;
}
void func(void)
{
int i;
i=func2();
ret = i;
}
void func1(void)
{
int i;
i=func2();
}
28. 宏调 用
在相同处理例程被定 义 为 宏 时,它 们 将会在被 调 用的 位置 进行 内联 扩展。 这将 消 除代码的生成和增进效率。
实例
调 用函数
abs 。
(优化前的 C 语言程序)
extern int a,b,c;
int abs(x)
int x;
{ return x>=0?x:-x; }
void f(void)
{
a=abs(b);
b=abs(c);
}
(优化后的 C 语言程序)
#define abs(x) ((x)>=0?(x):-(x))
extern int a,b,c;
void f(void)
{
a=abs(b);
b=abs(c);
}
29. 声明 原 型
具有 字符 类型 或 无符号字符 类型 参 数的函数,必须在被 调 用之前进行 原 型声明以 消 除冗余类型 转换 代码的 输出 。
实例
调 用具有 字符 类型 或 无符号字符 类型 参 数的函数
sub1 。
(优化前的 C 语言程序)
char a;
unsigned char b;
void func(void)
{
sub1(a,b);
}
(优化后的 C 语言程序)
void sub1(char, unsigned char);
char a;
unsigned char b;
void func(void)
{
sub1(a,b);
}
30. 尾递归 的优化
如 果函数进行了一个函数 调 用, 观察 函数 调 用是 否 可以 移动 到 调 用 源 函数的 尾端 。 这可同时增进 ROM 的效率和执行速度。
尾递归 优化会在 满足 以下所有条件 后 执行:
调 用 源 函数不会在 堆栈 上 放置 它的 参 数 或返回 值 地址 。
该 函数 调 用之 后即 是 RTS 指令。
实例
调 用函数
sub 并更 新 外 部 变量的值。
(优化前的 C 语言程序)
void g(void);
int a;
void main(void)
{
if (a==0) a++;
else{
g();
a+=2;
}
}
(优化后的 C 语言程序)
void g(void);
int a;
void main(void)
{
if (a==0) a++;
else{
a+=2;
g();
}
}
31. 增进 参 数 传递 的方式
要缩减代码大小,必须 调整参 数列 出 时的 顺 序以使 参 数之间没有间 隙 。
(优化前的 C 语言程序)
long rtn;
void func(char,short,char);
void main()
{
short a;
char b,c;
func(b,a,c);
}
void func(char x,short y,char z)
{
rtn=x*y+z;
}
(优化后的 C 语言程序)
long rtn;
void func(char,char,short);
void main()
{
short a;
char b,c;
func(b,c,a);
}
void func(char x,char y,short z)
{
rtn=x*y+z;
}
32. 将 切换 语句重 写 为表
如 果 case 语句所执行的 与
switch 关联 的处理任务是相似的,
switch 语句必须使用一个表来编码以缩减目标大小。
实例
根 据函数
a 的值 转移 到一个函数。
(优化前的 C 语言程序)
extern void f1(void);
extern void f2(void);
extern void f3(void);
extern void f4(void);
extern void f5(void);
extern int a;
void sub(void)
{
switch(a){
case 0:f1();break;
case 1:f2();break;
case 2:f3();break;
case 3:f4();break;
case 4:f5();break;
}
}
(优化后的 C 语言程序)
extern void f1(void);
extern void f2(void);
extern void f3(void);
extern void f4(void);
extern void f5(void);
extern int a;
void sub(void)
{
static int (*key[5])()=
{f1,f2,f3,f4,f5};
(*key[a])();
}
33. 编 写
Case 语句 跳转至 相同标 签 的程序
包含 相同表达式的
case 语句必须 组合 在一 起 ,以减 少转移 指令的数目并缩减目标大小。
(优化前的 C 语言程序)
long ll;
void func(void)
{
char c;
switch(c){
case 0: ll=0; break;
case 1: ll=0; break;
case 2: ll=1; break;
case 3: ll=1; break;
case 4: ll=2; break;
}
}
(优化后的 C 语言程序)
long ll;
void func(void)
{
char c;
switch(c){
case 0:
case 1: ll=0; break;
case 2:
case 3: ll=1; break;
case 4: ll=2; break;
}
}
34. 转移 到 直 接在指定语句下编码的函数
如 果函数 调 用 出现 在函数的 尾端 ,必须将 调 用目标函数 直 接 放置 在函数 调 用下 面 。
如 果 尾递归 优化正在进行,必须将 调 用目标函数 直 接 放置 在函数 调 用下 面 ,以 充分利 用此优化来产生 删 除函数 调 用代码的效果。由于 删 除了函数 调 用代码,程序的大小将会缩减而处理速度将会增 加 。
实例
从 函数
main 调 用函数
func 。
(优化前的 C 语言程序)
int a;
void func();
void func()
{
a++;
}
void main()
{
a=0;
func();
}
(优化后的 C 语言程序)
int a;
void func();
void main()
{
a=0;
func();
}
void func()
{
a++;
}