在嵌入式系统中优化C代码的技巧

嵌入式技术

1344人已加入

描述

C中的以下简单技巧专门用于程序内存空间优化. 这些对于处理具有有限闪存的低成本 8 位微控制器的嵌入式系统程序员特别有用。虽然在这种情况下汇编语言是最好的选择,但(几乎所有年轻的)硬件工程师现在更喜欢使用 C 语言,即使程序是一个相对较短的控制程序。这 10 个技巧已使用 XC8 编译器(v1.42,免费版)进行了测试,以显示在增强型中档 8 位 XLP PICmicro(PIC16F1824)上应用每个代码片段之前和之后所涉及的程序存储器字节量。这些代码片段除了提供概念证明之外没有什么特别之处。可以在本文末尾列出的参考资料中找到更聪明(和复杂)的技巧。

技巧#1: 尽可能使用简短的数学表达式。

示例 1: 改用: 
void main(void)
{
int a, b ;
 
  a = (b – 1) * 3 ;
}
void main(void)
{
int a, b ;
 
  a = (b – 1) ;
  一 = 一 + 一 + 一 ;
}
使用的程序存储器字节 = 50 使用的程序存储器字节 = 25

技巧 #2: 使用多个 if 指令(没有 else)来替换 switch 指令。switch 指令的每个 case(没有默认 case)都被替换为 if 指令(没有 else)。但是,如果 switch 指令以默认情况终止,则此技巧无关紧要。

示例 2: 改用: 
void main(void)
{
int a, b ;
 
  开关 (a)
  { 案例 0: b = a + 5 ; 休息 ;
    案例 1: b = a * 5 ;休息 ;
    情况 2: b = a – 5 ;休息 ;
  }
}
void main(void)
{
int a, b ;
 
  如果 (a == 0) b = a + 5 ;
  如果 (a == 1) b = a * 5 ;
  如果 (a == 2) b = a – 5 ;
}
使用的程序存储器字节 = 79 使用的程序存储器字节 = 74

技巧 #3: 假设我们要扫描一组特定的键盘触摸(仅按字母顺序排列,不区分大小写):

示例 3: 改用:( 
也使代码运行得更快)
void main(void)
{
char chx ;
 
  if (chx == 'a' || chx == 'A') b = a + 5 ;
  if (chx == 'm' || chx == 'M') b = a – 10 ;
  if (chx == 't' || chx == 'T') b = a * 25 ;
}
void main(void)
{
char chx ;
 
  //小写,
  // 注意,仅按字母顺序

  chx = chx | 0x20 ;
  if (chx == 'a') b = a + 5 ;
  if (chx == 'm') b = a – 10 ;
  if (chx == 't') b = a * 25 ;
}
使用的程序存储器字节 = 84 使用的程序存储器字节 = 77

技巧 #4: 尽可能使用 if 指令而不使用 else。在此代码中,我们假设条件 (a == 0) 更频繁地发生(在现实世界中使用设计时)。因此,我们首先提出: b = 0 ; 然后,我们用一个简单的 if 指令(没有 else)来考虑备用状态(不太频繁)。

示例 4: 改用: 
void main(void)
{
int a, b, c ;
 
  如果 (a == 0) b = 0 ; 否则 b = (a – c) * 100 ;
}
void main(void)
{
int a, b, c ;
 
 b = 0 ; 如果 (a) b = (a – c) * 100 ;
}
使用的程序存储器字节 = 64 使用的程序内存字节 = 63 (可以忽略不计,但通常,代码源包含许多 if/else 指令
 

技巧 #5: 使用一维表,而不是二维表。将二维表(行索引 i 和列索引 j)转换为一维表(索引 k)相对容易,假设索引计算如下: k = i * N + j ;其中 N 是总列数。(所有索引都是从零开始的)

示例 5: 改用: 
void main(void)
{
  const char *TabMois[] =
                           {“一月”,“二月”,“三月”,“四月”,“五月”,“六月”,
                           “七月”,“八月”,“九月”, “十月”、“十一月”、“十二月”} ;
  char ch1 = TabMois[0][0],ch2 = TabMois[0][1],
          ch3 = TabMois[0][2];
}
void main(void)
{
  const char TabMois[] =
                   “JanFebMarAprMayJunJulAugSepOctNovDec” ;
  char ch1 = TabMois[0],ch2 = TabMois[1],
          ch3 = TabMois[2];
}
使用的程序存储器字节 = 149 使用的程序存储器字节 = 68

技巧 #6: 在计算表达式时,尽可能使用整数值而不是浮点值。假设一个电池电压的值在 10.5 到 14.2 伏之间变化,步长为 0.1 伏。我们要计算每分钟的平均值(对于 1s 数据采集系统)。将 10 位数字计数测量值累积为整数变量,而不将其(每秒)转换为有意义的电压测量值(浮点值)。此转换仅在最后一步中进行一次。  

示例 6: 改用: 
int Measure (unsigned int canal)
{ //这里涉及更多代码来配置运河
   //...
    return ((ADRESH<<8) + ADRESL) ;
}
void main(void)
{
float Vbat, Vmean=0 ; 整数一,cnt = 60;
  while (cnt) 
  { if (TMR1IF) { Vbat = Measure(a) * 4.88 ;
    Vmean += Vbat ; cnt-; TMR1IF = 0 ; }
  }
  Vmean /= 60 ;
}
int Measure (unsigned int canal)
{ //这里涉及更多代码来配置运河
   //...
    return ((ADRESH<<8) + ADRESL) ;
}
void main(void)
{
float Vmean ; int a,cnt,Vbat,Vbat60=0;
  while (cnt) 
  { if (TMR1IF) { Vbat = Measure(a) ; Vbat60 += Vbat ;
    cnt-; TMR1IF = 0 ; }
  }
  Vmean = (Vbat60 * 4.88) / 60 ;
}
使用的程序存储器字节 = 841 使用的程序存储器字节 = 570

技巧#7: 指令可以用多种方式编写。看看这个结构:

示例 7: 改用: 
void main(void)
{
  for (a = 10 ; a > 0 ; a–) b = c + a ;
}
void main(void)
{
  for (a = 10 ; a– ; ) b = c + a ;
}
使用的程序存储器字节 = 43 使用的程序存储器字节 = 27

技巧 #8: 修改包含乘法与常数 k 的数学表达式,并修改它以使用除以 1/k

示例 8: 改用: 
void main(void)
{
float a, b, c ;
  a = (b + c) * 0.1 ;
}
void main(void)
{
float a, b, c ;
  a = (b + c) / 10.0 ;
}
使用的程序存储器字节 = 570 使用的程序存储器字节 = 559

技巧 #9: 尽可能对 int 或 long 类型 使用无符号值。注意将数字保持在区间 {0, ..., INT_MAX} 或 {0, ..., LONG_MAX}

示例 9: 改用: 
void main(void)
{
int Vbat ; // 1, 2, ..., 1023
  Vbat = 1023 / Vbat ; //案例 1
  Vbat = (2048L * 15) / Vbat ; //案例 2
}
void main(void)
{
int Vbat ; // 1, 2, ..., 1023
  Vbat = 1023U / Vbat ; //案例 1
  Vbat = (2048UL * 15) / Vbat ; //案例 2
}
情况 1:使用的程序存储器字节 = 102

 

情况 2:使用的程序存储器字节 = 160

情况 1:使用的程序存储器字节 = 73

 

情况 2:使用的程序存储器字节 = 114

技巧 #10: 在 if 指令中重新安排测试:

例 10: 改用:
void main(void)
{
int a, b ;
  如果 (a – b) b = (a – 5) * 100 ; //情况 1
  if (b > a) b = (a – 5) * 100 ; //情况 2
  if (b – a > 0) b = (a – 5) * 100 ; //案例 3
}
void main(void)
{
int a, b ;
  如果 (a != b) b = (a – 5) * 100 ; //情况 1
  if (a < b) b = (a - 5) * 100 ; //情况 2
  if (a – b < 0) b = (a - 5) * 100 ; //案例 3
}
情况 1:使用的程序存储器字节 = 67

 

情况 2:使用的程序存储器字节 = 62

情况 3:使用的程序存储器字节 = 77

情况 1:使用的程序存储器字节 = 58

 

情况 2:使用的程序存储器字节 = 62

情况 3:使用的程序存储器字节 = 65

  审核编辑:汤梓红
 
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分