设为首页 加入收藏

TOP

编写高效的C程序与C代码优化(二)
2016-05-01 02:25:09 】 浏览:1425
Tags:编写 高效 程序 代码 优化
被定义成:起点是对该变量的一次空间分配,终点是在下次空间分配之前的最后一次使用之间。在这个范围内,变量的值是合法的,是活的。在生存范围之外,变量不再被使用,是死的,它的寄存器可以供其他变量使用,这样,编译器就可以安排更多的变量到寄存器当中。
可分配到寄存器的变量需要的寄存器数量等于经过生命范围重叠的变量的数目,如果这个数目超过可用的寄存器的数量,有些变量就必须被暂时的存储到内存中。这种处理叫做“泄漏(spilling)”。
编译器优先释放最不频繁使用的变量,将释放的代价降到最低。可以通过以下方式避免变量的“释放”:

  • 限制活跃变量的最大数目:通常可以使用简单小巧的表达式,在函数内部不使用太多的变量。把大的函数分割成更加简单的、更加小巧的多个函数,也可能会有所帮助。

  • 使用关键字register修饰最经常使用的变量:告诉编译器这个变量将会被经常用到,要求编译器使用非常高的优先级将此变量分配到寄存器中。尽管如此,在某些情况下,变量还是可能被泄漏。

    变量类型 / Variable Types

    C编译器支持基本的变量类型:char、short、int、long(signed、unsigned)、float、double。为变量定义最恰当的类型,非常重要,因为这样可以减少代码和数据的长度,可以非常显著的提高效率。

    局部变量 / Local variables

    如果可能,局部变量要避免使用char和short。对于char和short类型,编译器在每次分配空间以后,都要将这种局部变量的尺寸减少到8位或16位。这对于符号变量来说称为符号扩展,对无符号变量称为无符号扩展。这种操作是通过将寄存器左移24或16位,然后再有符号(或无符号的)右移同样的位数来实现的,需要两条指令(无符号字节变量的无符号扩展需要一条指令)。
    这些移位操作可以通过使用int和unsigned int的局部变量来避免。这对于那些首先将数据调到局部变量然后利用局部变量进行运算的情况尤其重要。即使数据以8位或16位的形式输入或输出,把他们当作32位来处理仍是有意义的。
    我们来考虑下面的三个例子函数:

    int wordinc (int a) {      return a + 1; } short shortinc (short a) {      return a + 1; } char charinc (char a) {      return a + 1; }

    他们的运算结果是相同的,但是第一个代码片断要比其他片断运行的要快。

    指针 / Pointers

    如果可能,我们应该使用结构体的引用作为参数,也就是结构体的指针,否则,整个结构体就会被压入堆栈,然后传递,这会降低速度。程序适用值传递可能需要几K字节,而一个简单的指针也可以达到同样的目的,只需要几个字节就可以了。
    如果在函数内部不会改变结构体的内容,那么就应该将参数声明为const型的指针。举个例子:

    void print_data_of_a_structure (const Thestruct  *data_pointer) {      ...printf contents of the structure... }

    这个例子代码告知编译器在函数内部不会改变外部结构体的内容,访问他们的时候,不需要重读。还可以确保编译器捕捉任何修改这个只读结构体的代码,给结构体以额外的保护。

    指针链 / Pointer chains

    指针链经常被用来访问结构体的信息,比如,下面的这段常见的代码:

    typedef struct { int x, y, z; } Point3; typedef struct { Point3 *pos, *direction; } Object; void InitPos1(Object *p) {     p->pos->x = 0;     p->pos->y = 0;     p->pos->z = 0; }

    代码中,处理器在每次赋值操作的时候都要重新装载p->pos,因为编译器不知道p->pos->x不是p->pos的别名。更好的办法是将p->pos缓存成一个局部变量,如下:

    void InitPos2(Object *p) {      Point3 *pos = p->pos;     pos->x = 0;      pos->y = 0;     pos->z = 0; }

    另一个可能的方法是将Point3结构体包含在Object结构体中,完全避免指针的使用。

    条件的执行 / Conditional Execution

    条件执行主要用在if语句中,同时也会用到由关系运算(<,==,>等)或bool运算(&&, !等)组成的复杂的表达式。尽可能的保持if和else语句的简单是有好处的,这样才能很好的条件化。关系表达式应该被分成包含相似条件的若干块。
    下面的例子演示了编译器如何使用条件执行:

    int g(int a, int b, int c, int d) {     if(a > 0 && b > 0 && c < 0 && d < 0)  //分组化的条件被捆绑在一起
            return a + b + c + d;     return -1; }

    条件被分组,便以其能够条件化他们。

    Boolean表达式和范围检查 / Boolean Expressions & Range checking

    有一种常见的boolean表达式被用来检查是否一个变量取值在某个特定的范围内,比方说,检查一个点是否在一个窗口内。

    bool PointInRectangelArea (Point p, Rectangle *r) {     return (p.x >= r->xmin && p.x < r->xmax && p.y >= r->ymin && p.y < r->ymax); }

    这里还有一个更快的方法:把(x >= min && x < max) 转换成 (unsigned)(x-min) < (max-min). 尤其是min为0时,更为有效。下面是优化后的代码:

    bool PointInRectangelArea (Point p, Rectangle *r) {     return ((unsigned) (p.x - r->xmin) < r->xmax && (unsigned) (p.y - r->ymin) < r->ymax); }

    Boolean表达式&与零的比较 / Boolean Expressions & Compares with zero

    在比较(CMP)指令后,相应的处理器标志位就会被设置。这些标志位也可以被其他的指令设置,诸如MOV, ADD, AND, MUL, 也就是基本的数学和逻辑运算指令(数据处理指令)。假如一条数据处理指令要设置这些标志位,那么N和Z标志位的设置方法跟把数字和零比较的设置方法是一样的。N标志位表示结果是不是负数,Z标志位表示结果是不是零。
    C语言中,处理器中的N和Z标志位对应的有符号数的关系运算符是x < 0, x >= 0, x == 0, x != 0,无符号数对应的是x == 0, x != 0 (or x > 0)。
    C语言中,每用到一个关系运算符,编译器就会产生一个比较指令。如果关系运算符是上面的其中一个,在数据处理指令紧跟比较指令的情况下,编译器就会将比较指令优化掉。比如:

    int aFunction(int x, int y) {     if (x + y < 0)         return 1;     else
            return 0; }

    这样做,会在关键循环中节省比较指令,使代码长度减少,效率增加。C语言中没有借位(carry)标志位和溢出(overflow)标志位的概念,所以如果不使用内嵌汇编语言,要访问C和V标志位是不可能的。尽管如此,编译器支持借位标志位(无符号数溢出),比方说:

    int sum(int x, int y) {      int res;      res = x + y;      if ((unsigned) res < (unsigned) x) // carry set  //         res++;      return res; }    

    惰性评估计算 / Lazy eva luation Exploitation

    在类似与这样的 if(a>10 && b=4) 语句中, 确保AND表达式的第一部分最有可能为false, 结果第二部分极有可能不被执行.

    用switch() 代替if...else...,在条件选择比较多的情况下,可以用if…else…else…

首页 上一页 1 2 3 4 5 下一页 尾页 2/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇一起talk C栗子吧( 第一百四十回.. 下一篇指针和数组的掌握以及内存的管理

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目