让你的 C 程序更有效率的 10 种方法

fmms 13年前
     <p><span id="result_box" lang="zh-CN"><span>任何代码</span><span>的</span><span>美丽</span><span>不仅在于</span><span>找到</span><span>一个给定的</span><span>问题</span><span>的</span><span>解决方案</span><span>,</span><span>但</span><span>在</span><span>它的简单性</span><span>,</span><span>有效性</span><span>,</span><span>紧凑性和</span><span>效率</span><span>(内存)</span><span>。</span><span>设计</span><span>的代码</span><span>比</span><span>实际执行</span><span>更难</span><span> 。</span><span>因此,</span><span>每</span><span>一个</span><span>程序员当用C语言开发时,都应该</span><span>保持这些</span><span>基本的东西</span><span>在</span><span>头脑</span><span>中。</span></span></p>    <p><span id="result_box" lang="zh-CN"><span> </span><span> </span><span>本文向你介绍规范你的C代码的10种方法。</span></span></p>    <p><strong>1. <span id="result_box" lang="zh-CN" class="short_text">避免不必要的函数调用</span></strong></p>    <p>考虑下面的2个函数:</p>    <blockquote>     <p>void str_print( char *str )<br /> {<br />     int i;<br />     for ( i = 0; i < strlen ( str ); i++ ) {<br />         printf("%c",str[ i ] );<br />     }<br /> }</p>    </blockquote>    <blockquote>     void str_print1 ( char *str )     <br /> {     <br />     int len;     <br />     len = strlen ( str );     <br />     for ( i = 0; i < len; i++ ) {     <br />         printf("%c",str[ i ] );     <br />     }     <br /> }    </blockquote>    <p><span id="result_box" lang="zh-CN"><span>请</span><span>注意</span><span> </span><span>这两个函数</span><span>的</span><span>功能</span><span>相似</span><span>。</span><span>然而,</span><span>第一个函数</span><span>调用</span><span>strlen()函数</span><span>多次</span><span>,</span><span>而第二个</span><span>函数只</span><span>调用</span><span>函数strlen(</span><span>)</span><span>一次。</span><span>因此</span><span>第一个函数</span><span>性能</span><span>明显比</span><span>第二个</span><span>好</span><span>。</span></span></p>    <p><strong><span lang="zh-CN"><span>2、</span></span><span id="result_box" lang="zh-CN" class="short_text"><span>避免</span><span>不必要</span><span>的</span><span>内存引用</span></span></strong></p>    <p><span lang="zh-CN" class="short_text"><span>这次我们再用2个例子来对比解释:</span></span></p>    <blockquote>     int multiply ( int *num1 , int *num2 )     <br /> {     <br />     *num1 = *num2;     <br />     *num1 += *num2;     <br />     return *num1;     <br /> }    </blockquote>    <blockquote>     int multiply1 ( int *num1 , int *num2 )     <br /> {     <br />     *num1 = 2 * *num2;     <br />     return *num1;     <br /> }    </blockquote>    <p><span id="result_box" lang="zh-CN"><span>同样</span><span>,</span><span>这两个函数</span><span>具有类似的功能</span><span>。</span><span>所不同的是</span><span>在第一个函数</span><span>(</span><span> </span></span>1 for reading *num1 , 2 for reading *num2 and 2 for writing to *num1<span id="result_box" lang="zh-CN"><span>)</span><span>有5</span><span>个内存的引用</span><span>,</span><span>而</span><span>在</span><span>第二个函数</span><span>是</span><span>只有2个</span><span>内存引用</span><span>(</span></span>one for reading *num2 and one for writing to *num1<span id="result_box" lang="zh-CN"><span>)</span><span>。</span><span>现在</span><span>你认为</span><span>哪一个</span><span>好些</span><span>?</span></span></p>    <p><strong>3、节约内存<span id="result_box" lang="zh-CN" class="short_text"><span>(</span><span>内存</span><span>对齐和</span><span>填充</span><span>的</span><span>概念</span></span>)</strong></p>    <blockquote>     <p>struct {<br />     char c;<br />     int i;<br />     short s;<br /> }str_1;<strong><br /> </strong></p>    </blockquote>    <blockquote>     struct {     <br />     char c;     <br />     short s;     <br />     int i;     <br /> }str_2;    </blockquote>    <p>假设一个字符需要1个字节,short占用2个字节和int需要4字节的内存。起初,我们会认为上面定义的结构是相同的,因此占据相同数量的内存。然而,而str_1占用12个字节,第二个结构只需要8个字节?这怎么可能呢?</p>    <p>请注意,在第一个结构,3个不同的4个字节被分配到三种数据类型,而在第二个结构的前4个自己char和short可以被采用,int可以采纳在第二个的4个字节边界(一共8个字节)。</p>    <p><strong>4、</strong><span id="result_box" lang="zh-CN"><strong>使用无符号整数,而不是整数的,如果你知道的值将永远是否定的。</strong></span></p>    <p><span id="result_box" lang="zh-CN"><strong> </strong><span>有些</span><span>处理器可以处理</span><span>无符号</span><span>的</span><span>整数</span><span>比有符号整数的运算速度要快。</span><span>(</span><span>这也是</span><span>很好</span><span>的</span><span>实践,</span><span>帮助</span></span>self-documenting代码<span id="result_box" lang="zh-CN"><span>)</span><span>。</span></span></p>    <p><strong><span lang="zh-CN">5、</span></strong><span id="result_box" lang="zh-CN" class="short_text"><strong><span>在</span><span>一个</span><span>逻辑</span><span>条件语句中常数项永远在</span><span>左侧。</span></strong></span></p>    <blockquote>     <p>int x = 4;<br /> if ( x = 1 ) {<br />     x = x + 2;<br />     printf("%d",x);          // Output is 3<br /> }</p>    </blockquote>    <blockquote>     int x = 4;     <br /> if ( 1 = x ) {     <br />     x = x + 2;     <br />     printf("%d",x);   // Compilation error     <br /> }    </blockquote>    <p><span id="result_box" lang="zh-CN"><span>使用</span><span class="atn">“</span><span>=”</span><span>赋值</span><span>运算符</span><span>,替代</span><span class="atn">“=</span><span>=”相等</span><span>运算符,这是个常见的输入错误。</span><span> </span><span>常数项</span><span>放在左侧,</span><span>将产生一个</span><span>编译时错误</span><span>,让</span><span>你</span><span>轻松</span><span>捕获</span><span>你的错误</span><span>。</span><span>注:</span><span>“=”</span><span>是赋值运算符</span><span>。</span> <span class="hps">b = 1</span><span>会设置</span><span>变量b</span><span>等于</span><span>值1</span><span>。</span> <span class="hps">“==”</span><span>相等运算符</span><span>。</span><span>如果</span><span>左侧</span><span>等于</span><span>右侧</span><span>,返回true,</span><span>否则返回false。</span></span></p>    <p><span id="result_box" lang="zh-CN"><span>6、</span></span><span id="result_box" lang="zh-CN" class="short_text"><span>在可能的情况下</span><span>使用</span></span>typedef替代macro。<span id="result_box" lang="zh-CN" class="short_text"><span>当然有时候你无法避免macro,但是typedef更好。</span></span></p>    <blockquote>     <p>typedef int* INT_PTR;<br /> INT_PTR a , b;<br /> # define INT_PTR int*;<br /> INT_PTR a , b;</p>    </blockquote>    <p><span id="result_box" lang="zh-CN"><span>在这个</span><span>宏定义中</span><span>,</span><span>a是一个</span><span>指向整数的指针</span><span>,</span><span>而</span><span>b是</span><span>只有</span><span>一个整数</span><span>声明</span><span>。</span><span>使用typedef</span> <span class="hps">a和b都是</span><span> </span><span>整数</span><span>的</span><span>指针</span><span>。</span></span></p>    <p><strong>7、</strong><span id="result_box" lang="zh-CN"><strong>确保声明和定义是静态的,除非您希望从不同的文件中调用该函数</strong><span><strong>。</strong></span></span></p>    <p><span id="result_box" lang="zh-CN"><span>在同一文件函数对其他函数可见,才称之为静态函数。</span><span>它</span><span>限制其他</span><span>访问内部函数,如果</span><span>我们希望</span><span>从</span><span>外界</span><span>隐藏</span><span>该函数</span><span>。</span><span>现在</span><span>我们并不</span><span>需要为内部函数创建头文件,其他看不到该函数。</span></span></p>    <p><span id="result_box" lang="zh-CN"><span>静态</span><span>声明一个函数</span><span>的</span><span>优点</span><span>包括:</span></span></p>    <p><span id="result_box" lang="zh-CN"><span>A)</span><span>两个或两个以上</span><span>具有相同名称</span><span>的</span><span>静态</span><span>函数</span><span>,</span><span>可用于</span><span>在不同的文件</span><span>。</span></span></p>    <p><span id="result_box" lang="zh-CN"><span>B)</span><span>编译消耗</span><span>减少</span><span>,因为没有</span><span>外部符号</span><span>处理</span><span>。</span></span></p>    <p><span id="result_box" lang="zh-CN"><span>让</span><span>我们</span><span>做</span><span>更好的</span><span>理解</span><span>,下面的例子</span><span>:</span></span></p>    <blockquote>     <p><br /> /*first_file.c*/<br /> static int foo ( int a )<br /> {<br /> /*Whatever you want to in the function*/<br /> }<br /> /*second_file.c*/<br /> int foo ( int )<br /> int main()<br /> {<br />     foo();      // This is not a valid function call as the function foo can only be called by any other function within first_file.c where it is defined.<br />     return 0;<br /> }</p>    </blockquote>    <p><span id="result_box" lang="zh-CN"><strong><span>8、使用</span></strong></span><em>Memoization</em><span id="result_box" lang="zh-CN"><strong><span>,以避免</span><span>递归重复</span><span>计算</span></strong><br /> <br /> <span>考虑</span></span><span lang="zh-CN"><span>Fibonacci</span></span><span id="result_box" lang="zh-CN"><span>(</span></span><span>斐波那契</span><span id="result_box" lang="zh-CN"><span>)问题</span><span>;</span></span><span lang="zh-CN"><span>Fibonacci</span></span><span id="result_box" lang="zh-CN"><span>问题是可以</span><span>通过</span><span>简单</span><span>的</span><span>递归方法</span><span>来解决:</span></span></p>    <blockquote>     <p><span lang="zh-CN"><span>int fib ( n )<br /> {<br />     if ( n == 0 || n == 1 ) {<br />         return 1;<br />     }<br />     else {<br />         return fib( n - 2 ) + fib ( n - 1 );<br />     }<br /> }<br /> </span></span></p>    </blockquote>    <p><span id="result_box" lang="zh-CN" class="short_text"><span>注:</span><span>在</span><span>这里</span><span>,</span><span>我们考虑</span></span><span lang="zh-CN"><span>Fibonacci</span></span><span id="result_box" lang="zh-CN"><span> 系列从</span></span><span id="result_box" lang="zh-CN" class="short_text"><span>1开始</span><span>,</span><span>因此,</span><span>该系列</span><span>看起来:</span><span>1,</span><span>1</span><span>,</span><span>2</span><span>,</span><span>3</span><span>,</span><span>5</span><span>,</span><span>8</span><span>,</span><span>...</span></span></p>    <p><a href="/misc/goto?guid=4958183169206006359"><img title="04114621_jeub.png" border="0" alt="04114621_jeub.png" src="https://simg.open-open.com/show/e87fff9988517985efcf3e8aea87e198.jpg" /></a></p>    <p><span id="result_box" lang="zh-CN"><span>注意:从</span><span>递归树</span><span>,</span><span>我们</span><span>计算</span><span>fib(3)</span><span>函数2次,</span><span>fib</span><span>(2)函数3次。</span><span>这是</span><span>相同函数的重复计算。</span><span>如果n</span><span>非常大,fib</span><span><n</span><span>(</span><span>i)</span><span>函数增长i<n。解决这一问题的快速方法将是计算函数值1次,存储在一些地方,需要时计算,而非一直重复计算。</span></span></p>    <p><span id="result_box" lang="zh-CN"><span>这个简单的技术叫做</span></span><em>Memoization</em><span id="result_box" lang="zh-CN"><span>,可以被用在递归,加强计算速度。</span></span><span id="result_box" lang="zh-CN"><span><br /> <br /> </span></span><span id="result_box" lang="zh-CN"><span>fibonacci 函数</span></span><em>Memoization</em><span id="result_box" lang="zh-CN"><span>的代码,应该是下面的这个样子:</span></span></p>    <blockquote>     <p><span lang="zh-CN"><span>int calc_fib ( int n )<br /> {<br />     int val[ n ] , i;<br />     for ( i = 0; i <=n; i++ ) {<br />         val[ i ] = -1;         // Value of the first n + 1 terms of the fibonacci terms set to -1<br />     }<br />     val[ 0 ] = 1;                 // Value of fib ( 0 ) is set to 1<br />     val[ 1 ] = 1;            // Value of fib ( 1 ) is set to 1<br />     return fib( n , val );<br /> }<br /> int fib( int n , int* value )<br /> {<br />     if ( value[ n ] != -1 ) {<br />         return value[ n ];              // Using memoization<br />     }<br />     else {<br />         value[ n ] = fib( n - 2 , value ) + fib ( n - 1 , value );          // Computing the fibonacci term<br />     }<br />     return value[ n ];                // Returning the value<br /> }<br /> </span></span></p>    </blockquote>    <p>这里calc_fib( n )函数被main()调用。</p>    <p><strong>9、</strong><span id="result_box" lang="zh-CN"><strong><span>避免</span>悬空指针和野指针</strong><br /> <br /> <span>一个指针的</span><span>指向</span><span>对象</span><span>已被删除</span><span>,那么就成了悬空指针。</span><span>野</span><span>指针是</span><span>那些</span><span>未初始化</span><span>的</span><span>指针</span><span>,</span><span>需要注意的是</span><span>野</span><span>指针</span><span>不</span><span>指向</span><span>任何</span><span>特定的内存位置</span><span>。</span></span></p>    <blockquote>     <p>void dangling_example()<br /> {<br />     int *dp = malloc ( sizeof ( int ));<br />     /*........*/<br />     free( dp );              // dp is now a dangling pointer<br />     dp = NULL;        // dp is no longer a dangling pointer<br /> }</p>    </blockquote>    <blockquote>     void wild_example()     <br /> {     <br />     int *ptr;        // Uninitialized pointer     <br />     printf("%u"\n",ptr );     <br />     printf("%d",*ptr );     <br /> }    </blockquote>    <p>当遭遇这些指针,程序通常是”怪异“的表现。</p>    <p>10、 <span id="result_box" lang="zh-CN"><span>永远记住</span><span>释放你分配给程序的任何内存。上面的例子就是如果释放dp指针(我们使用malloc()函数调用)。</span></span></p>    <p><span lang="zh-CN"><span>原文:<a href="/misc/goto?guid=4958183169943736465">http://www.fortystones.com/tips-to-make-c-program-effective/</a></span></span></p>