# 超全 | 只有高手才知道的C语言高效编程与代码优化方法（二）

```if( val == 1)
dostuff1();else if (val == 2)
dostuff2();else if (val == 3)
ostuff3();```

```switch( val )
{    case 1: dostuff1(); break;    case 2: dostuff2(); break;    case 3: dostuff3(); break;
}```

Switch允许我们不做额外的测试。

```if(a==1) {
} else if(a==2) {
} else if(a==3) {
} else if(a==4) {
} else if(a==5) {
} else if(a==6) {
} else if(a==7) {
} else if(a==8)

{
}```

```if(a<=4</=) {    if(a==1)     {
}  else if(a==2)  {
}  else if(a==3)  {
}  else if(a==4)   {

}
}else{    if(a==5)  {
} else if(a==6)   {
} else if(a==7)  {
} else if(a==8)  {
}
}```

```if(a<=4</=)
{    if(a<=2)
{        if(a==1)
{            /* a is 1 */
}        else
{            /* a must be 2 */
}
}    else
{        if(a==3)
{            /* a is 3 */
}        else
{            /* a must be 4 */
}
}
}else{    if(a<=6)
{        if(a==5)
{            /* a is 5 */
}        else
{            /* a must be 6 */
}
}    else
{        if(a==7)
{            /* a is 7 */
}        else
{            /* a must be 8 */
}
}
}</=</=```

c=getch();switch(c){ case 'A': { do something; break; } case 'H': { do something; break; } case 'Z': { do something; break; }}

c=getch();switch(c){ case 0: { do something; break; } case 1: { do something; break; } case 2: { do something; break; }}

switch语句vs查找表

Switch的应用场景如下：

• 调用一到多个函数；
• 设置变量值或者返回一个值；
• 执行一到多个代码片段；

```char * Condition_String1(int condition) {         switch(condition) {           case 0: return "EQ";            case 1: return "NE";            case 2: return "CS";            case 3: return "CC";            case 4: return "MI";            case 5: return "PL";            case 6: return "VS";            case 7: return "VC";            case 8: return "HI";            case 9: return "LS";            case 10: return "GE";            case 11: return "LT";            case 12: return "GT";            case 13: return "LE";            case 14: return "";            default: return 0;  }}char * Condition_String2(int condition) {          if ((unsigned) condition >= 15) return 0;             return   "EQ\0NE\0CS\0CC\0MI\0PL\0VS\0VC\0HI\0LS\0GE\0LT\0GT\0LE\0\0" +       3 * condition;
}```

```int fact1_func (int n){    int i, fact = 1;    for (i = 1; i <= n;="" i++)=""  =""  fact="" *="i;"   (fact);
}int fact2_func(int n){    int i, fact = 1;    for (i = n; i != 0; i--)
fact *= i;    return (fact);
}```

`for( i=0;  i<10;  i++){ ... }`

i从0循环到9。如果我们不介意循环计数的顺序，我们可以这样写：

`for( i=10; i--; ) { ... }`

`for(i=10; i; i--){}`

`for(i=10; i!=0; i--){}`

//Original Code :for(i=0; i<100; i++){ stuff();}for(i=0; i<100; i++){ morestuff();}

//It would be better to do:for(i=0; i<100; i++){ stuff(); morestuff();}

```for(i=0 ; i<100 ; i++)
{    func(t,i);
}
-
-
-
void func(int w,d){
lots of stuff.
}```

```func(t);
-
-
-
void func(w){    for(i=0 ; i<100 ; i++)
{        //lots of stuff.
}
}```

for(i=0; i<3; i++){ something(i);}//is less efficient than

something(0);something(1);something(2);

`for(i=0;i< limit;i++) { ... }`

block-sie的值设置为8仅仅适用于测试的目的，只要我们重复执行“loop-contents”相同的次数，都会有很好的效果。

```//Example 1#include#define BLOCKSIZE (8)void main(void){int i = 0;int limit = 33;  /* could be anything */int blocklimit;/* The limit may not be divisible by BLOCKSIZE,
* go as near as we can first, then tidy up.
*/blocklimit = (limit / BLOCKSIZE) * BLOCKSIZE;/* unroll the loop in blocks of 8 */while( i < blocklimit )
{            printf("process(%d)\n", i);            printf("process(%d)\n", i+1);            printf("process(%d)\n", i+2);            printf("process(%d)\n", i+3);            printf("process(%d)\n", i+4);            printf("process(%d)\n", i+5);            printf("process(%d)\n", i+6);            printf("process(%d)\n", i+7);            /* update the counter */
i += 8;

}/*
* There may be some left to do.
* This could be done as a simple for() loop,
* but a switch is faster (and more interesting)
*/if( i < limit )
{              /* Jump into the case at the place that will allow
* us to finish off the appropriate number of items.
*/

switch( limit - i )
{              case 7 : printf("process(%d)\n", i); i++;              case 6 : printf("process(%d)\n", i); i++;              case 5 : printf("process(%d)\n", i); i++;              case 4 : printf("process(%d)\n", i); i++;              case 3 : printf("process(%d)\n", i); i++;              case 2 : printf("process(%d)\n", i); i++;              case 1 : printf("process(%d)\n", i);
}
}

} * go as near as we can first, then tidy up.
*/blocklimit = (limit / BLOCKSIZE) * BLOCKSIZE;/* unroll the loop in blocks of 8 */while( i < blocklimit ){            printf("process(%d)\n", i);            printf("process(%d)\n", i+1);            printf("process(%d)\n", i+2);            printf("process(%d)\n", i+3);            printf("process(%d)\n", i+4);            printf("process(%d)\n", i+5);            printf("process(%d)\n", i+6);            printf("process(%d)\n", i+7);            /* update the counter */    i += 8;

}/*
* There may be some left to do.
* This could be done as a simple for() loop,
* but a switch is faster (and more interesting)
*/if( i < limit )
{    /* Jump into the case at the place that will allow
* us to finish off the appropriate number of items.
*/

switch( limit - i )
{              case 7 : printf("process(%d)\n", i); i++;              case 6 : printf("process(%d)\n", i); i++;              case 5 : printf("process(%d)\n", i); i++;              case 4 : printf("process(%d)\n", i); i++;              case 3 : printf("process(%d)\n", i); i++;              case 2 : printf("process(%d)\n", i); i++;              case 1 : printf("process(%d)\n", i);    }
}

}```

```//Example - 1int countbit1(uint n){  int bits = 0;  while (n != 0)
{    if (n & 1) bits++;
n >>= 1;
}  return bits;
}//Example - 2int countbit2(uint n){   int bits = 0;   while (n != 0)
{      if (n & 1) bits++;      if (n & 2) bits++;      if (n & 4) bits++;      if (n & 8) bits++;
n >>= 4;
}   return bits;
}```

```found = FALSE;for(i=0;i<10000;i++)
{    if( list[i] == -99 )
{
found = TRUE;
}
}if( found ) printf("Yes, there is a -99. Hooray!\n");```

```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");```

```int f1(int a, int b, int c, int d) {   return a + b + c + d;
}int g1(void) {   return f1(1, 2, 3, 4);
}int f2(int a, int b, int c, int d, int e, int f) {  return a + b + c + d + e + f;
}ing g2(void) { return f2(1, 2, 3, 4, 5, 6);
}```

• 尽量保证函数使用少于四个参数。这样就不会使用栈来存储参数值；
• 如果函数需要多于四个的参数，尽量确保使用后面参数的价值高于让其存储于栈所付出的代价；
• 通过指针传递参数的引用而不是传递参数结构体本身；
• 将参数放入一个结构体并通过指针传入函数，这样可以减少参数的数量并提高可读性；
• 尽量少用占用两个字大小的long类型参数。对于需要浮点类型的程序，double也因为占用两个字大小而应尽量少用；
• 避免函数参数既存在于寄存器又存在于栈中（称之为参数拆分）。现在的编译器对这种情况处理的不够高效：所有的寄存器变量也会放入到栈中；
• 避免变参。变参函数将参数全部放入栈。

• 避免调用其他函数：包括那些转而调用C库的函数（比如除法或者浮点数操作函数）；
• 对于简短的函数使用__inline修饰（）。

```__inline int square(int x) {   return x * x;
}#include double length(int x, int y){    return sqrt(square(x) + square(y));
}```

• 没有函数调用负担。函数调用处直接替换为函数体，因此没有诸如读取寄存器变量等性能消耗。
• 更小的参数传递消耗。由于不需要拷贝变量，传递参数的消耗更小。如果参数是常量，编译器可以提供更好的优化。

• 浮点除法很慢。浮点除法比加法或者乘法慢两倍。通过使用常量将除法转换为乘法（例如，x=x/3.0可以替换为x=x*(1.0/3.0)）。常量的除法在编译期间计算；
• 使用float代替double。Float类型的变量消耗更好的内存和寄存器，并由于精度低而更加高效。如果精度够用，尽可能使用float；
• 避免使用先验函数。先验函数，例如sin、exp和log是通过一系列的乘法和加法实现的（使用了精度扩展）。这些操作比通常的乘法至少慢十倍；
• 简化浮点运算表达式。编译器并不能将应用于整型操作的优化手段应用于浮点操作。 例如，3*(x/3)可以优化为x，而浮点运算就会损失精度。因此，如果知道结果正确，进行必要手工浮点优化是有必要的。

• 尽量不在循环中使用++和–。例如：while(n–){}，这有时难于优化；
• 减少全局变量的使用；
• 除非像声明为全局变量，使用static修饰变量为文件内访问；
• 尽可能使用一个字大小的变量（int、long等），使用它们（而不是char，short，double，位域等）机器可能运行的更快；
• 不使用递归。递归可能优雅而简单，但需要太多的函数调用；
• 不在循环中使用sqrt开平方函数，计算平方根非常消耗性能；
• 一维数组比多维数组更快；
• 编译器可以在一个文件中进行优化-避免将相关的函数拆分到不同的文件中，如果将它们放在一起，编译器可以更好的处理它们（例如可以使用inline）；
• 单精度函数比双精度更快；
• 浮点乘法运算比浮点除法运算更快-使用val*0.5而不是val/2.0；
• 加法操作比乘法快-使用val+val+val而不是val*3；
• put()函数比printf()快，但不灵活；
• 使用#define宏取代常用的小函数；
• 二进制/未格式化的文件访问比格式化的文件访问更快，因为程序不需要在人为可读的ASCII和机器可读的二进制之间转化。如果你不需要阅读文件的内容，将它保存为二进制；
• 如果你的库支持mallopt()函数（用于控制malloc），尽量使用它。MAXFAST的设置，对于调用很多次malloc工作的函数由很大的性能提升。
• 如果一个结构一秒钟内需要多次创建并销毁，试着设置mallopt选项。

0 条评论

• ### 【秘籍】程序员高薪面试技巧

面试就像高考，分数优异，不一定能进入好大学，面试亦是如此，能力强不一定能进入到自己心仪的公司，因为这个不仅和技术有关，还和自己的综合素质与临场发挥有关。今天老九...

• ### 程序员面试的真正核心点是.....

程序员面试 作为面试官，他们从哪些角度来考察一个应聘的程序员是否合适公司的岗位呢？ 通常情况下，面试官都会在与你的交谈中考量你的职业规划，综合能力，及行业经...

• ### 面试须知的五大要点，也许能让你快人一步

1. 说得太少 尤其是那些开放式的问题，如“请介绍下你自己”或“请讲一下你曾经解决过的复杂问题”。面试官会通过你对这些技术和非技术问题的回答来评估你的激情。他们...

• ### HashMap 源码分析

HashMap 源码分析 1. 在阅读源码时做了大量的注释，并且做了一些测试分析源码内的执行流程，由于博客篇幅有限，并且代码阅读起来没有 IDE 方便，所以在...

• ### JDK容器学习之HashMap (二) ： 读写逻辑详解

Map读写实现逻辑说明 前一篇博文 JDK容器学习之HashMap (一) ： 底层存储结构分析 分析了HashMap的底层存储数据结构 通过put(k,v...

• ### 【Java】基础篇-HashMap

public V put(K key, V value) { // 对key的hashCode()做hash return putVal(ha...

• ### Java8 hashmap

HashMap是java集合类中一种常见的集合类型，在面试中多次被问到。这里根据面试中的问题稍微整理一下。

• ### HashMap原理及源码分析

1. HashMap原理 2. HashMap源码分析 3. HashMap在java8中的改变