前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C语言代码优化的一些经验及小技巧(三)

C语言代码优化的一些经验及小技巧(三)

作者头像
正念君
发布2019-11-28 19:41:06
2.2K0
发布2019-11-28 19:41:06
举报
文章被收录于专栏:嵌入式大杂烩

循环展开

简单的循环可以展开以获取更好的性能,但需要付出代码体积增加的代价。循环展开后,循环计数应该越来越小从而执行更少的代码分支。如果循环迭代次数只有几次,那么可以完全展开循环,以便消除循坏带来的负担。例如:

代码语言:javascript
复制
for(i=0; i<3; i++)
{
    something(i);
}

展开为:

代码语言:javascript
复制
something(0);
something(1);
something(2);

这可以非常可观的节省性能,原因是代码不用每次循环需要检查和增加i的值。

if判断条件的顺序

if的判断条件中概率最大的情况应放在前面。例子:

代码语言:javascript
复制
if (1 == condition)
{

}
else if (2 == condition)
{

}
else
{

}

此处,若condition为1的概率大较大则把if (1 == condition)放在前面,若condition为2概率大较大则把if (2 == condition)放在前面,如:

代码语言:javascript
复制
if (2 == condition)
{

}
else if (1 == condition)
{

}
else
{

}

这里有个小细节:在用if判断某个变量与某个常量是否相等时,可以把常量写在前面变量写在后面,如:

代码语言:javascript
复制
if (2 == condition)

2放在前面,condition放在后面。这样的好处就是当你漏敲了一个=号时,编译器会指出你的这个错误。

尽早退出循环

通常,循环并不需要全部都执行。例如,如果我们在从数组中查找一个特殊的值,一经找到,我们应该尽可能早的断开循环。例如:如下循环从10000个整数中查找是否存在-99。

代码语言:javascript
复制
found = FALSE;
for(i=0;i<10000;i++)
{
    if( list[i] == -99 )
    {
        found = TRUE;
    }
}

if( found ) 
{
    printf("Yes, there is a -99. Hooray!\n");
}

这段代码无论我们是否查找得到,循环都会全部执行完。更好的方法是一旦找到我们查找的数字就终止继续查询。把程序修改为:

代码语言:javascript
复制
found = FALSE;
for(i=0;i<10000;i++)
{
    if( list[i] == -99 )
    {
        found = TRUE;
        break;
    }
}

if( found ) 
{
    printf("Yes, there is a -99. Hooray!\n");
}

假如待查数据位于第23个位置上,程序便会执行23次,从而节省9977次循环。

使用位运算替代四则运算

在许多古老的微处理器上, 位运算比加减运算略快, 通常位运算比乘除法运算要快很多。在现代架构中, 位运算的运算速度通常与加法运算相同,但仍然快于乘法运算。所以通常乘以或除以2n可以使用位运算来代替四则运算,如

代码语言:javascript
复制
a = a * 8;
a = a / 8;
a = a % 8;

修改为:

代码语言:javascript
复制
a = a << 3;
a = a >> 3;
a = a & 7;

以空间换时间

在内存比较充足的情况下,可以使用空间来换取时间。比如使用查表法,把一些可能的结果事先保存到表中。例如求阶乘通常的做法是:

代码语言:javascript
复制
long factorial(int i)
{
    if (i == 0)
        return 1;
    else
        return i * factorial(i - 1);
}

若是空间比较足,而且所需的结果都能列举出来,则代码可以修改为:

代码语言:javascript
复制
static long factorial_table[] = {1, 1, 2, 6, 24, 120, 720  /* etc */ };
long factorial(int i)
{
    return factorial_table[i];
}

使用复合赋值语句

增加一个变量的值有两种方式,如:a = a + 5a += 5。存在两种增加一个变量值的方法有何意义呢?K&R C设计者认为复合赋值符可以让程序员把代码写得更清楚些。另外,编译器可以产生更为紧凑的代码。现在,a = a + 5和a += 5之间的差别不再那么显著,而且现代的编译器为这两种表达式产生优化代码并无多大问题。但是,要考虑类似如下的语句:

代码语言:javascript
复制
a[2*(y-6*f(x))] = a[2*(y-6*f(x))] + 5;
a[2*(y-6*f(x))] += 5;

此处a为数组。在第一种形式种,由于编译器无从知道f函数是否具有副作用,所以它必须两次计算数组a的下标表达式的值。而在第二种形式中,下标表达式只需计算一次,所以第二种形式效率更高。并且,从书写的角度看,第一种形式的下标表达式需要书写两次,而第二种形式只需书写一次。

尽量使循环体内的工作量达到最小化

循环中,随着循环次数的增加,会加大对系统资源的消耗。我们应当确认一些操作是否必须放在循环体内。示例代码:

代码语言:javascript
复制
for (i = 0; i < n; i++)
{
    tmp += i;
    sum = tmp;
}

这是个求和操作,但是这里每循环一次,就要进行一次sum = tmp;操作,这样的写法很浪费资源。这一条语句完全可以移至循环体外:

代码语言:javascript
复制
for (i = 0; i < n; i++)
{
    tmp += i;
}
sum = tmp;

这样,sum = tmp;语句只执行一次,不仅可以调高程序效率,也提高了可读性。同时,我们还可以考虑类似这样的代码是否有必要封装成一个函数供多个地方调用。

以上就是本次的分享,如有错误,欢迎指出!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-08-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 循环展开
  • if判断条件的顺序
  • 尽早退出循环
  • 使用位运算替代四则运算
  • 以空间换时间
  • 使用复合赋值语句
  • 尽量使循环体内的工作量达到最小化
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档