<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="http://unfoldingneurons.com/"
	>

<channel>
	<title>朱文昊 Albert Zhu &#187; C 语言</title>
	<atom:link href="http://zhuwenhao.com/category/%e6%8a%80%e6%9c%af/%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e8%af%ad%e8%a8%80/c-%e8%af%ad%e8%a8%80/feed/" rel="self" type="application/rss+xml" />
	<link>http://zhuwenhao.com</link>
	<description>朱文昊的中文博客－－专注技术，向往自由</description>
	<lastBuildDate>Thu, 10 May 2012 07:20:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>深入理解C语言</title>
		<link>http://zhuwenhao.com/968/%e6%8a%80%e6%9c%af/%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e8%af%ad%e8%a8%80/c-%e8%af%ad%e8%a8%80/%e6%b7%b1%e5%85%a5%e7%90%86%e8%a7%a3c%e8%af%ad%e8%a8%80/</link>
		<comments>http://zhuwenhao.com/968/%e6%8a%80%e6%9c%af/%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e8%af%ad%e8%a8%80/c-%e8%af%ad%e8%a8%80/%e6%b7%b1%e5%85%a5%e7%90%86%e8%a7%a3c%e8%af%ad%e8%a8%80/#comments</comments>
		<pubDate>Fri, 04 Nov 2011 13:01:03 +0000</pubDate>
		<dc:creator>朱文昊 Albert Zhu</dc:creator>
				<category><![CDATA[C 语言]]></category>

		<guid isPermaLink="false">http://zhuwenhao.com/?p=968</guid>
		<description><![CDATA[轉載自本站友情鏈接的coolshell，原文鏈接。
朱文昊評註：感謝Ritchie等先驅，他們的聰明才智和貢獻令人欽佩萬分。C語言的很多特性都有歷史的影子，隨著時間的流逝歷史逐漸沈積為基石。這樣，要學好用好C語言，除了可以多瞭解一下計算機科學的發展史，更應該多瞭解一些硬件相關的東西。推薦延伸閱讀資料：《C語言缺陷於陷阱》以及《C語言專家編程》
&#160;
Dennis Ritchie  过世了，他发明了C语言，一个影响深远并彻底改变世界的计算机语言。一门经历40多年的到今天还长盛不衰的语言，今天很多语言都受到C的影响，C++，Java，C#，Perl， PHP， Javascript，  [...]]]></description>
			<content:encoded><![CDATA[<p>轉載自本站友情鏈接的coolshell，<a href="http://coolshell.cn/articles/5761.html" target="_blank">原文鏈接</a>。</p>
<blockquote><p>朱文昊評註：感謝Ritchie等先驅，他們的聰明才智和貢獻令人欽佩萬分。C語言的很多特性都有歷史的影子，隨著時間的流逝歷史逐漸沈積為基石。這樣，要學好用好C語言，除了可以多瞭解一下計算機科學的發展史，更應該多瞭解一些硬件相關的東西。推薦延伸閱讀資料：《C語言缺陷於陷阱》以及《C語言專家編程》</p>
<p>&nbsp;</p></blockquote>
<p>Dennis Ritchie  过世了，他发明了C语言，一个影响深远并彻底改变世界的计算机语言。一门经历40多年的到今天还长盛不衰的语言，今天很多语言都受到C的影响，C++，Java，C#，Perl， PHP， Javascript， 等等。但是，你对C了解吗？相信你看过本站的《<a href="http://coolshell.cn/articles/945.html">C语言的谜题</a>》还有《<a href="http://coolshell.cn/articles/873.html">谁说C语言很简单？</a>》，这里，我再写一篇关于深入理解C语言的文章，一方面是缅怀Dennis，另一方面是告诉大家应该如何学好一门语言。（顺便注明一下，下面的一些例子来源于<a href="http://www.slideshare.net/olvemaudal/deep-c">这个slides</a>）</p>
<p>首先，我们先来看下面这个经典的代码：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p968code9'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p9689"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code" id="p968code9"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #993333;">int</span> a <span style="color: #339933;">=</span> <span style="color: #0000dd;">42</span><span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span>“<span style="color: #339933;">%</span>d\n”<span style="color: #339933;">,</span> a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>从这段代码里你看到了什么问题？我们都知道，这段程序里少了一个#include &lt;stdio.h&gt; 还少了一个return 0;的返回语句。</p>
<p>不过，让我们来深入的学习一下，</p>
<ul>
<li>这段代码在C++下无法编译，因为C++需要明确声明函数</li>
<li>这段代码在C的编译器下会编译通过，因为在编译期，编译器会生成一个printf的函数定义，并生成.o文件，链接时，会找到标准的链接库，所以能编译通过。</li>
<li> 但是，你知道这段程序的退出码吗？在ANSI-C下，退出码是一些未定义的垃圾数。但在C89下，退出码是3，因为其取了printf的返回值。为什么printf函数返回3呢？因为其输出了’4′, ’2′,’\n’ 三个字符。而在C99下，其会返回0，也就是成功地运行了这段程序。你可以使用gcc的 -std=c89或是-std=c99来编译上面的程序看结果。</li>
<li>另外，我们还要注意main()，在C标准下，如果一个函数不要参数，应该声明成main(void)，而main()其实相当于main(…)，也就是说其可以有任意多的参数。</li>
</ul>
<p>我们再来看一段代码：</p>
<p>&nbsp;</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p968code10'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p96810"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
</pre></td><td class="code" id="p968code10"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
&nbsp;
<span style="color: #993333;">void</span> f<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #993333;">static</span> <span style="color: #993333;">int</span> a <span style="color: #339933;">=</span> <span style="color: #0000dd;">3</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">static</span> <span style="color: #993333;">int</span> b<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">int</span> c<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #339933;">++</span>a<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>b<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>c<span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;a=%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;b=%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;c=%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> c<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #009900;">&#123;</span>
&nbsp;
f<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
f<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
f<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>这个程序会输出什么？</p>
<ul>
<li>我相信你对a的输出相当有把握，就分别是4，5，6，因为那个静态变量。</li>
<li>对于c呢，你应该也比较肯定，那是一堆乱数。</li>
<li>但是你可能不知道b的输出会是什么？答案是1，2，3。为什么和c不一样呢？因为，如果要初始化，每次调用函数里，编译器都要初始化函数栈空间，这太费性能了。但是c的编译器会初始化静态变量为0，因为这只是在启动程序时的动作。</li>
<li>全局变量同样会被初始化。</li>
</ul>
<p>说到全局变量，你知道 静态全局变量和一般全局变量的差别吗？是的，对于static 的全局变量，其对链接器不可以见，也就是说，这个变量只能在当前文件中使用。</p>
<p>我们再来看一个例子：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p968code11'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p96811"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="code" id="p968code11"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
&nbsp;
<span style="color: #993333;">void</span> foo<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #993333;">int</span> a<span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">void</span> bar<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #993333;">int</span> a <span style="color: #339933;">=</span> <span style="color: #0000dd;">42</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #009900;">&#123;</span>
&nbsp;
bar<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
foo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>你知道这段代码会输出什么吗？A) 一个随机值，B) 42。A 和 B都对（在“<a href="http://coolshell.cn/articles/4907.html">在函数外存取局部变量的一个比喻</a>”文中的最后给过这个例子），不过，你知道为什么吗？</p>
<ul>
<li>如果你使用一般的编译，会输出42，因为我们的编译器优化了函数的调用栈（重用了之前的栈），为的是更快，这没有什么副作用。反正你不初始化，他就是随机值，既然是随机值，什么都无所谓。</li>
<li>但是，如果你的编译打开了代码优化的开关，-O，这意味着，foo()函数的代码会被优化成main()里的一个inline函数，也就是说没有函数调用，就像宏定义一样。于是你会看到一个随机的垃圾数。</li>
</ul>
<p>下面，我们再来看一个示例：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p968code12'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p96812"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="code" id="p968code12"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
&nbsp;
<span style="color: #993333;">int</span> b<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span>“<span style="color: #0000dd;">3</span>”<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">3</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">int</span> c<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span>“<span style="color: #0000dd;">4</span>”<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">4</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #993333;">int</span> a <span style="color: #339933;">=</span> b<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> c<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span>“<span style="color: #339933;">%</span>d\n”<span style="color: #339933;">,</span> a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>这段程序会输出什么？，你会说是，3，4，7。但是我想告诉你，这也有可能输出，4，3，7。为什么呢？ 这是因为，在C/C++中，表达的评估次序是没有标准定义的。编译器可以正着来，也可以反着来，所以，不同的编译器会有不同的输出。你知道这个特性以后，你就知道这样的程序是没有可移植性的。</p>
<p>我们再来看看下面的这堆代码，他们分别输出什么呢？</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p968code13'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p96813"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code" id="p968code13"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> a<span style="color: #339933;">=</span><span style="color: #0000dd;">41</span><span style="color: #339933;">;</span> a<span style="color: #339933;">++;</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span>“<span style="color: #339933;">%</span>d\n”<span style="color: #339933;">,</span> a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">int</span> a<span style="color: #339933;">=</span><span style="color: #0000dd;">41</span><span style="color: #339933;">;</span> a<span style="color: #339933;">++</span> <span style="color: #339933;">&amp;</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span>“<span style="color: #339933;">%</span>d\n”<span style="color: #339933;">,</span> a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">int</span> a<span style="color: #339933;">=</span><span style="color: #0000dd;">41</span><span style="color: #339933;">;</span> a<span style="color: #339933;">++</span> <span style="color: #339933;">&amp;&amp;</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span>“<span style="color: #339933;">%</span>d\n”<span style="color: #339933;">,</span> a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">int</span> a<span style="color: #339933;">=</span><span style="color: #0000dd;">41</span><span style="color: #339933;">;</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>a<span style="color: #339933;">++</span> <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">42</span><span style="color: #009900;">&#41;</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span>“<span style="color: #339933;">%</span>d\n”<span style="color: #339933;">,</span> a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">int</span> a<span style="color: #339933;">=</span><span style="color: #0000dd;">41</span><span style="color: #339933;">;</span> a <span style="color: #339933;">=</span> a<span style="color: #339933;">++;</span> <a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span>“<span style="color: #339933;">%</span>d\n”<span style="color: #339933;">,</span> a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>只有示例一，示例三，示例四输出42，而示例二和五的行为则是未定义的。关于这种未定义的东西是因为Sequence Points的影响（Sequence Points是一种规则，也就是程序执行的序列点，在两点之间的表达式只能对变量有一次修改），因为这会让编译器不知道在一个表达式顺列上如何存取变量的值。比如a = a++，a + a++，不过，在C中，这样的情况很少。</p>
<p>下面，再看一段代码：（假设int为4字节，char为1字节）</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p968code14'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p96814"><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code" id="p968code14"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">struct</span> X <span style="color: #009900;">&#123;</span> <span style="color: #993333;">int</span> a<span style="color: #339933;">;</span> <span style="color: #993333;">char</span> b<span style="color: #339933;">;</span> <span style="color: #993333;">int</span> c<span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d,&quot;</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> X<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">struct</span> Y <span style="color: #009900;">&#123;</span> <span style="color: #993333;">int</span> a<span style="color: #339933;">;</span> <span style="color: #993333;">char</span> b<span style="color: #339933;">;</span> <span style="color: #993333;">int</span> c<span style="color: #339933;">;</span> <span style="color: #993333;">char</span> d<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> Y<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>这个代码会输出什么?</p>
<p>a) 9，10<br />
b)12, 12<br />
c)12, 16</p>
<p>答案是C，我想，你一定知道字节对齐，是向4的倍数对齐。</p>
<ul>
<li>但是，你知道为什么要字节对齐吗？还是因为性能。因为这些东西都在内存里，如果不对齐的话，我们的编译器就要向内存一个字节一个字节的取，这样一来，struct X，就需要取9次，太浪费性能了，而如果我一次取4个字节，那么我三次就搞定了。所以，这是为了性能的原因。</li>
<li>但是，为什么struct Y不向12 对齐，却要向16对齐，因为char d; 被加在了最后，当编译器计算一个结构体的尺寸时，是边计算，边对齐的。也就是说，编译器先看到了int，很好，4字节，然后是 char，一个字节，而后面的int又不能填上还剩的3个字节，不爽，把char b对齐成4，于是计算到d时，就是13 个字节，于是就是16啦。但是如果换一下d和c的声明位置，就是12了。</li>
</ul>
<p>另外，再提一下，上述程序的printf中的%d并不好，因为，在64位下，sizeof的size_t是unsigned long，而32位下是 unsigned int，所以，C99引入了一个专门给size_t用的%zu。这点需要注意。在64位平台下，C/C++ 的编译需要注意很多事。你可以参看《<a href="http://coolshell.cn/articles/3512.html">64位平台C/C++开发注意事项</a>》。</p>
<p>下面，我们再说说编译器的Warning，请看代码：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p968code15'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p96815"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code" id="p968code15"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #993333;">int</span> a<span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>考虑下面两种编译代码的方式 ：</p>
<ul>
<li>cc -Wall a.c</li>
<li>cc -Wall -O a.c</li>
</ul>
<p>前一种是不会编译出a未初化的警告信息的，而只有在-O的情况下，才会有未初始化的警告信息。这点就是为什么我们在makefile里的CFLAGS上总是需要-Wall和 -O。</p>
<p>最后，我们再来看一个指针问题，你看下面的代码：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p968code16'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p96816"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="code" id="p968code16"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
&nbsp;
<span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #993333;">int</span> a<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%x<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%x<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> a<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%x<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>amp<span style="color: #339933;">;</span>a<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%x<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>amp<span style="color: #339933;">;</span>a<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>假如我们的a的地址是：0Xbfe2e100, 而且是32位机，那么这个程序会输出什么？</p>
<ul>
<li>第一条printf语句应该没有问题，就是 bfe2e100</li>
<li>第二条printf语句你可能会以为是bfe2e101。那就错了，a+1，编译器会编译成 a+ 1*sizeof(int)，int在32位下是4字节，所以是加4，也就是bfe2e104</li>
<li>第三条printf语句可能是你最头疼的，我们怎么知道a的地址？我不知道吗？可不就是bfe2e100。那岂不成了a==&amp;a啦？这怎么可能？自己存自己的？也许很多人会觉得指针和数组是一回事，那么你就错了。如果是 int *a，那么没有问题，因为a是指针，所以 &amp;a 是指针的地址，a 和 &amp;a不一样。但是这是数组啊a[]，所以&amp;a其实是被编译成了 &amp;a[0]。</li>
<li>第四条printf语句就很自然了，就是bfe2e104。还是不对，因为是&amp;a是数组，被看成int(*)[5]，所以sizeof(a)是5，也就是5*sizeof(int)，也就是bfe2e114。</li>
</ul>
<p>看过这么多，你可能会觉得C语言设计得真扯淡啊。不过我要告诉下面几点Dennis当初设计C语言的初衷：</p>
<p><strong>1）相信程序员，不阻止程序员做他们想做的事。</strong></p>
<p><strong>2）保持语言的简洁，以及概念上的简单。</strong></p>
<p><strong>3）保证性能，就算牺牲移植性。</strong></p>
<p>今天很多语言进化得很高级了，语法也越来越复杂和强大，但是C语言依然光芒四射，Dennis离世了，但是C语言的这些设计思路将永远不朽。</p>
<p><strong>（请勿用于商业用途，转载时请注明作者和出处）</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://zhuwenhao.com/968/%e6%8a%80%e6%9c%af/%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e8%af%ad%e8%a8%80/c-%e8%af%ad%e8%a8%80/%e6%b7%b1%e5%85%a5%e7%90%86%e8%a7%a3c%e8%af%ad%e8%a8%80/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>gcc扩展，在Linux Kernel中的使用示例</title>
		<link>http://zhuwenhao.com/387/%e6%8a%80%e6%9c%af/%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e8%af%ad%e8%a8%80/c-%e8%af%ad%e8%a8%80/gcc%e6%89%a9%e5%b1%95%ef%bc%8c%e5%9c%a8linux-kernel%e4%b8%ad%e7%9a%84%e4%bd%bf%e7%94%a8%e7%a4%ba%e4%be%8b/</link>
		<comments>http://zhuwenhao.com/387/%e6%8a%80%e6%9c%af/%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e8%af%ad%e8%a8%80/c-%e8%af%ad%e8%a8%80/gcc%e6%89%a9%e5%b1%95%ef%bc%8c%e5%9c%a8linux-kernel%e4%b8%ad%e7%9a%84%e4%bd%bf%e7%94%a8%e7%a4%ba%e4%be%8b/#comments</comments>
		<pubDate>Thu, 13 May 2010 07:10:34 +0000</pubDate>
		<dc:creator>朱文昊 Albert Zhu</dc:creator>
				<category><![CDATA[C 语言]]></category>

		<guid isPermaLink="false">http://zhuwenhao.com/?p=387</guid>
		<description><![CDATA[GNC CC 是一个功能非常强大的跨平台 C 编译器，它对 C 语言提供了很多扩展，这些扩展对优化、目标代码布局、更安全的检查等方面提供了很强的支持。本文把支持 GNU 扩展的 C 语言称为 GNU C。 Linux 内核代码使用了大量的 GNU C 扩展，以至于能够编译 Linux 内核的唯一编译器是 GNU CC，以前甚至出现过编译 Linux 内核要使用特殊的 GNU CC 版本的情
况。本文是对 Linux 内核使用的 GNU C 扩展的一个汇总，希望当你读内核源码遇到不理解的语法和语义时，能从本文找到一个初步的解答，更详细的信息可以查看gcc.info。文中的例子取自 Linux  [...]]]></description>
			<content:encoded><![CDATA[<p>GNC CC 是一个功能非常强大的跨平台 C 编译器，它对 C 语言提供了很多扩展，这些扩展对优化、目标代码布局、更安全的检查等方面提供了很强的支持。本文把支持 GNU 扩展的 C 语言称为 GNU C。 Linux 内核代码使用了大量的 GNU C 扩展，以至于能够编译 Linux 内核的唯一编译器是 GNU CC，以前甚至出现过编译 Linux 内核要使用特殊的 GNU CC 版本的情<br />
况。本文是对 Linux 内核使用的 GNU C 扩展的一个汇总，希望当你读内核源码遇到不理解的语法和语义时，能从本文找到一个初步的解答，更详细的信息可以查看gcc.info。文中的例子取自 Linux 2.4.18。</p>
<p>语句表达式<br />
==========<br />
GNU C 把包含在括号中的复合语句看做是一个表达式，称为语句表达式，它可以出现在任何允许表达式的地方，你可以在语句表达式中使用循环、局部变量等，原本只能在复合语句中使用。例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code37'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38737"><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code" id="p387code37"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">++++</span> include<span style="color: #339933;">/</span>linux<span style="color: #339933;">/</span>kernel.<span style="color: #202020;">h</span>
<span style="color: #0000dd;">159</span><span style="color: #339933;">:</span> <span style="color: #339933;">#define min_t(type,x,y) \
160: ({ type __x = (x); type __y = (y); __x &amp;lt; __y ? __x: __y; })</span>
<span style="color: #339933;">++++</span> net<span style="color: #339933;">/</span>ipv4<span style="color: #339933;">/</span>tcp_output.<span style="color: #202020;">c</span>
<span style="color: #0000dd;">654</span><span style="color: #339933;">:</span> <span style="color: #993333;">int</span> full_space <span style="color: #339933;">=</span> min_t<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span><span style="color: #339933;">,</span> tp<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>window_clamp<span style="color: #339933;">,</span> tcp_full_space<span style="color: #009900;">&#40;</span>sk<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>复合语句的最后一个语句应该是一个表达式，它的值将成为这个语句表达式的值。这里定义了一个安全的求最小值的宏，在标准 C 中，通常定义为:</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code38'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38738"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p387code38"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#define min(x,y) ((x) &amp;lt; (y) ? (x) : (y))</span></pre></td></tr></table></div>

<p>这个定义计算 x 和 y 分别两次，当参数有副作用时，将产生不正确的结果，使用语句表达式只计算参数一次，避免了可能的错误。语句表达式通常用于宏定义。</p>
<p>Typeof<br />
======<br />
使用前一节定义的宏需要知道参数的类型，利用 typeof 可以定义更通用的宏，不必事先知道参数的类型，例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code39'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38739"><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code" id="p387code39"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">++++</span> include<span style="color: #339933;">/</span>linux<span style="color: #339933;">/</span>kernel.<span style="color: #202020;">h</span>
<span style="color: #0000dd;">141</span><span style="color: #339933;">:</span> <span style="color: #339933;">#define min(x,y) ({ \
142: const typeof(x) _x = (x); \
143: const typeof(y) _y = (y); \
144: (void) (&amp;amp;_x == &amp;amp;_y); \
145: _x &amp;lt; _y ? _x : _y; })</span></pre></td></tr></table></div>

<p>这里 typeof(x) 表示 x 的值类型，第 142 行定义了一个与 x 类型相同的局部变量 _x 并初使化为 x，注意第 144 行的作用是检查参数 x 和 y 的类型是否相同。typeof 可以用在任何类型可以使用的地方，通常用于宏定义。<br />
零长度数组<br />
======<br />
GNU C 允许使用零长度数组，在定义变长对象的头结构时，这个特性非常有用。例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code40'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38740"><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code" id="p387code40"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">++++</span> include<span style="color: #339933;">/</span>linux<span style="color: #339933;">/</span>minix_fs.<span style="color: #202020;">h</span>
<span style="color: #0000dd;">85</span><span style="color: #339933;">:</span> <span style="color: #993333;">struct</span> minix_dir_entry <span style="color: #009900;">&#123;</span>
<span style="color: #0000dd;">86</span><span style="color: #339933;">:</span> __u16 inode<span style="color: #339933;">;</span>
<span style="color: #0000dd;">87</span><span style="color: #339933;">:</span> <span style="color: #993333;">char</span> name<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #0000dd;">88</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>结构的最后一个元素定义为零长度数组，它不占结构的空间。在标准 C 中则需要定义数组长度为 1，分配时计算对象大小比较复杂。<br />
可变参数宏<br />
==========<br />
在 GNU C 中，宏可以接受可变数目的参数，就象函数一样，例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code41'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38741"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p387code41"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">++++</span> include<span style="color: #339933;">/</span>linux<span style="color: #339933;">/</span>kernel.<span style="color: #202020;">h</span>
<span style="color: #0000dd;">110</span><span style="color: #339933;">:</span> <span style="color: #339933;">#define pr_debug(fmt,arg...) \
111: printk(KERN_DEBUG fmt,##arg)</span></pre></td></tr></table></div>

<p>这里 arg 表示其余的参数，可以是零个或多个，这些参数以及参数之间的逗号构成 arg 的值，在宏扩展时替换 arg，例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code42'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38742"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p387code42"><pre class="c" style="font-family:monospace;">pr_debug<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%s:%d&quot;</span><span style="color: #339933;">,</span>filename<span style="color: #339933;">,</span>line<span style="color: #009900;">&#41;</span></pre></td></tr></table></div>

<p>扩展为</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code43'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38743"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p387code43"><pre class="c" style="font-family:monospace;">printk<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;&lt;7&gt;&quot;</span>  <span style="color: #ff0000;">&quot;%s:%d&quot;</span><span style="color: #339933;">,</span> filename<span style="color: #339933;">,</span> line<span style="color: #009900;">&#41;</span></pre></td></tr></table></div>

<p>使用 ## 的原因是处理 arg 不匹配任何参数的情况，这时 arg 的值为空，GNU C 预处理器在这种特殊情况下，丢弃 ## 之前的逗号，这样</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code44'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38744"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p387code44"><pre class="c" style="font-family:monospace;">pr_debug<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;success!<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span></pre></td></tr></table></div>

<p>扩展为</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code45'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38745"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p387code45"><pre class="c" style="font-family:monospace;">printk<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;&lt;7&gt;&quot;</span>  <span style="color: #ff0000;">&quot;success!<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span></pre></td></tr></table></div>

<p>注意最后没有逗号。<br />
标号元素<br />
========<br />
标准 C 要求数组或结构变量的初使化值必须以固定的顺序出现，在 GNU C 中，通过指定索引或结构域名，允许初始化值以任意顺序出现。指定数组索引的方法是在初始化值前写 &#8216;[INDEX] =&#8217;，要指定一个范围使用[FIRST ... LAST] =&#8217; 的形式，<br />
例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code46'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38746"><td class="line_numbers"><pre>1
2
</pre></td><td class="code" id="p387code46"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">+++++</span> arch<span style="color: #339933;">/</span>i386<span style="color: #339933;">/</span>kernel<span style="color: #339933;">/</span>irq.<span style="color: #202020;">c</span>
<span style="color: #0000dd;">1079</span><span style="color: #339933;">:</span> <span style="color: #993333;">static</span> <span style="color: #993333;">unsigned</span> <span style="color: #993333;">long</span> irq_affinity <span style="color: #009900;">&#91;</span>NR_IRQS<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span> <span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span> ... <span style="color: #202020;">NR_IRQS</span><span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> ~0UL <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>将数组的所有元素初使化为 ~0UL，这可以看做是一种简写形式。<br />
要指定结构元素，在元素值前写 &#8216;FIELDNAME:&#8217;，例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code47'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38747"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code" id="p387code47"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">++++</span> fs<span style="color: #339933;">/</span>ext2<span style="color: #339933;">/</span>file.<span style="color: #202020;">c</span>
<span style="color: #0000dd;">41</span><span style="color: #339933;">:</span> <span style="color: #993333;">struct</span> file_operations ext2_file_operations <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
<span style="color: #0000dd;">42</span><span style="color: #339933;">:</span> llseek<span style="color: #339933;">:</span> generic_file_llseek<span style="color: #339933;">,</span>
<span style="color: #0000dd;">43</span><span style="color: #339933;">:</span> read<span style="color: #339933;">:</span> generic_file_read<span style="color: #339933;">,</span>
<span style="color: #0000dd;">44</span><span style="color: #339933;">:</span> write<span style="color: #339933;">:</span> generic_file_write<span style="color: #339933;">,</span>
<span style="color: #0000dd;">45</span><span style="color: #339933;">:</span> ioctl<span style="color: #339933;">:</span> ext2_ioctl<span style="color: #339933;">,</span>
<span style="color: #0000dd;">46</span><span style="color: #339933;">:</span> mmap<span style="color: #339933;">:</span> generic_file_mmap<span style="color: #339933;">,</span>
<span style="color: #0000dd;">47</span><span style="color: #339933;">:</span> open<span style="color: #339933;">:</span> generic_file_open<span style="color: #339933;">,</span>
<span style="color: #0000dd;">48</span><span style="color: #339933;">:</span> release<span style="color: #339933;">:</span> ext2_release_file<span style="color: #339933;">,</span>
<span style="color: #0000dd;">49</span><span style="color: #339933;">:</span> fsync<span style="color: #339933;">:</span> ext2_sync_file<span style="color: #339933;">,</span>
<span style="color: #0000dd;">50</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>将结构 ext2_file_operations 的元素 llseek 初始化为 generic_file_llseek，元素 read 初始化为 genenric_file_read，依次类推。我觉得这是 GNU C 扩展中最好的特性之一，当结构的定义变化以至元素的偏移改变时，这种初始化方法仍然保证已知元素的正确性。对于未出现在初始化中的元素，其初值为 0。<br />
Case 范围<br />
=========<br />
GNU C 允许在一个 case 标号中指定一个连续范围的值，例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code48'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38748"><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code" id="p387code48"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">++++</span> arch<span style="color: #339933;">/</span>i386<span style="color: #339933;">/</span>kernel<span style="color: #339933;">/</span>irq.<span style="color: #202020;">c</span>
<span style="color: #0000dd;">1062</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'0'</span> ... <span style="color: #ff0000;">'9'</span><span style="color: #339933;">:</span> c <span style="color: #339933;">-=</span> <span style="color: #ff0000;">'0'</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
<span style="color: #0000dd;">1063</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'a'</span> ... <span style="color: #ff0000;">'f'</span><span style="color: #339933;">:</span> c <span style="color: #339933;">-=</span> <span style="color: #ff0000;">'a'</span><span style="color: #339933;">-</span><span style="color: #0000dd;">10</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
<span style="color: #0000dd;">1064</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'A'</span> ... <span style="color: #ff0000;">'F'</span><span style="color: #339933;">:</span> c <span style="color: #339933;">-=</span> <span style="color: #ff0000;">'A'</span><span style="color: #339933;">-</span><span style="color: #0000dd;">10</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'0'</span> ... <span style="color: #ff0000;">'9'</span><span style="color: #339933;">:</span></pre></td></tr></table></div>

<p>相当于</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code49'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38749"><td class="line_numbers"><pre>1
2
</pre></td><td class="code" id="p387code49"><pre class="c" style="font-family:monospace;"><span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'0'</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'1'</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'2'</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'3'</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'4'</span><span style="color: #339933;">:</span>
<span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'5'</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'6'</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'7'</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'8'</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'9'</span><span style="color: #339933;">:</span></pre></td></tr></table></div>

<p>声明的特殊属性<br />
==============<br />
GNU C 允许声明函数、变量和类型的特殊属性，以便手工的代码优化和更仔细的代码检查。要指定一个声明的属性，在声明后写</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code50'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38750"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p387code50"><pre class="c" style="font-family:monospace;">__attribute__ <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span> ATTRIBUTE <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></td></tr></table></div>

<p>其中 ATTRIBUTE 是属性说明，多个属性以逗号分隔。GNU C 支持十几个属性，这里介绍最常用的：<br />
* noreturn<br />
属性 noreturn 用于函数，表示该函数从不返回。这可以让编译器生成稍微优化的代码，最重要的是可以消除不必要的警告信息比如未初使化的变量。例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code51'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38751"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p387code51"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">++++</span> include<span style="color: #339933;">/</span>linux<span style="color: #339933;">/</span>kernel.<span style="color: #202020;">h</span>
<span style="color: #0000dd;">47</span><span style="color: #339933;">:</span> <span style="color: #339933;"># define ATTRIB_NORET __attribute__((noreturn)) ....</span>
<span style="color: #0000dd;">61</span><span style="color: #339933;">:</span> asmlinkage NORET_TYPE <span style="color: #993333;">void</span> do_exit<span style="color: #009900;">&#40;</span><span style="color: #993333;">long</span> error_code<span style="color: #009900;">&#41;</span></pre></td></tr></table></div>

<p>ATTRIB_NORET;<br />
* format (ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK)<br />
属性 format 用于函数，表示该函数使用 printf, scanf 或 strftime 风格的参数，使用这类函数最容易犯的错误是格式串与参数不匹配，指定 format 属性可以让编译器根据格式串检查参数类型。例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code52'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38752"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p387code52"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">++++</span> include<span style="color: #339933;">/</span>linux<span style="color: #339933;">/</span>kernel.<span style="color: #202020;">h</span><span style="color: #339933;">?</span>
<span style="color: #0000dd;">89</span><span style="color: #339933;">:</span> asmlinkage <span style="color: #993333;">int</span> printk<span style="color: #009900;">&#40;</span><span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span> fmt<span style="color: #339933;">,</span> ...<span style="color: #009900;">&#41;</span>
<span style="color: #0000dd;">90</span><span style="color: #339933;">:</span> __attribute__ <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>format <span style="color: #009900;">&#40;</span><a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html"><span style="color: #000066;">printf</span></a><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>表示第一个参数是格式串，从第二个参数起根据格式串检查参数。<br />
* unused<br />
属性 unused 用于函数和变量，表示该函数或变量可能不使用，这个属性可以避免编译器产生警告信息。<br />
* section (“section-name”)<br />
属性 section 用于函数和变量，通常编译器将函数放在 .text 节，变量放在.data 或 .bss 节，使用 section 属性，可以让编译器将函数或变量放在指定的节中。</p>
<p>GNU CC 预定义了两个标志符保存当前函数的名字，__FUNCTION__ 保存函数在源码中的名字，__PRETTY_FUNCTION__ 保存带语言特色的名字。在 C 函数中，这两个名字是相同的，在 C++ 函数中，__PRETTY_FUNCTION__ 包括函数返回类型等额外信息，Linux 内核只使用了 __FUNCTION__。</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code53'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38753"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code" id="p387code53"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">++++</span> fs<span style="color: #339933;">/</span>ext2<span style="color: #339933;">/</span>super.<span style="color: #202020;">c</span>
<span style="color: #0000dd;">98</span><span style="color: #339933;">:</span> <span style="color: #993333;">void</span> ext2_update_dynamic_rev<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> super_block <span style="color: #339933;">*</span>sb<span style="color: #009900;">&#41;</span>
<span style="color: #0000dd;">99</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
<span style="color: #0000dd;">100</span><span style="color: #339933;">:</span> <span style="color: #993333;">struct</span> ext2_super_block <span style="color: #339933;">*</span>es <span style="color: #339933;">=</span> EXT2_SB<span style="color: #009900;">&#40;</span>sb<span style="color: #009900;">&#41;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>s_es<span style="color: #339933;">;</span>
<span style="color: #0000dd;">101</span><span style="color: #339933;">:</span>
<span style="color: #0000dd;">102</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>le32_to_cpu<span style="color: #009900;">&#40;</span>es<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>s_rev_level<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span> EXT2_GOOD_OLD_REV<span style="color: #009900;">&#41;</span>
<span style="color: #0000dd;">103</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span>
<span style="color: #0000dd;">104</span><span style="color: #339933;">:</span>
<span style="color: #0000dd;">105</span><span style="color: #339933;">:</span> ext2_warning<span style="color: #009900;">&#40;</span>sb<span style="color: #339933;">,</span> __FUNCTION__<span style="color: #339933;">,</span>
<span style="color: #0000dd;">106</span><span style="color: #339933;">:</span> <span style="color: #ff0000;">&quot;updating to rev %d because of new feature flag, &quot;</span>
<span style="color: #0000dd;">107</span><span style="color: #339933;">:</span> <span style="color: #ff0000;">&quot;running e2fsck is recommended&quot;</span><span style="color: #339933;">,</span>
<span style="color: #0000dd;">108</span><span style="color: #339933;">:</span> EXT2_DYNAMIC_REV<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>这里 __FUNCTION__ 将被替换为字符串 “ext2_update_dynamic_rev”。虽然__FUNCTION__ 看起来类似于标准 C 中的 __FILE__，但实际上 __FUNCTION__是被编译器替换的，不象 __FILE__ 被预处理器替换。<br />
内建函数<br />
========<br />
GNU C 提供了大量的内建函数，其中很多是标准 C 库函数的内建版本，例如memcpy，它们与对应的 C 库函数功能相同，本文不讨论这类函数，其他内建函数的名字通常以 __builtin 开始。<br />
* __builtin_return_address (LEVEL)<br />
内建函数 __builtin_return_address 返回当前函数或其调用者的返回地址，参数LEVEL 指定在栈上搜索框架的个数，0 表示当前函数的返回地址，1 表示当前函数的调用者的返回地址，依此类推。例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code54'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38754"><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code" id="p387code54"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">++++</span> kernel<span style="color: #339933;">/</span>sched.<span style="color: #202020;">c</span>
<span style="color: #0000dd;">437</span><span style="color: #339933;">:</span> printk<span style="color: #009900;">&#40;</span>KERN_ERR <span style="color: #ff0000;">&quot;schedule_timeout: wrong timeout &quot;</span>
<span style="color: #0000dd;">438</span><span style="color: #339933;">:</span> <span style="color: #ff0000;">&quot;value %lx from %p<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> timeout<span style="color: #339933;">,</span>
<span style="color: #0000dd;">439</span><span style="color: #339933;">:</span> __builtin_return_address<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>* __builtin_constant_p(EXP)<br />
内建函数 __builtin_constant_p 用于判断一个值是否为编译时常数，如果参数EXP 的值是常数，函数返回 1，否则返回 0。例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code55'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38755"><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code" id="p387code55"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">++++</span> include<span style="color: #339933;">/</span>asm<span style="color: #339933;">-</span>i386<span style="color: #339933;">/</span>bitops.<span style="color: #202020;">h</span>
<span style="color: #0000dd;">249</span><span style="color: #339933;">:</span> <span style="color: #339933;">#define test_bit(nr,addr) \
250: (__builtin_constant_p(nr) ? \
251: constant_test_bit((nr),(addr)) : \
252: variable_test_bit((nr),(addr)))</span></pre></td></tr></table></div>

<p>很多计算或操作在参数为常数时有更优化的实现，在 GNU C 中用上面的方法可以根据参数是否为常数，只编译常数版本或非常数版本，这样既不失通用性，又能在参数是常数时编译出最优化的代码。<br />
* __builtin_expect(EXP, C)<br />
内建函数 __builtin_expect 用于为编译器提供分支预测信息，其返回值是整数表达式 EXP 的值，C 的值必须是编译时常数。例如：</p>

<div class="wp_codebox_msgheader"><span class="right"></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p387code56'); return false;">View Code</a> C</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p38756"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code" id="p387code56"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">++++</span> include<span style="color: #339933;">/</span>linux<span style="color: #339933;">/</span>compiler.<span style="color: #202020;">h</span>
<span style="color: #0000dd;">13</span><span style="color: #339933;">:</span> <span style="color: #339933;">#define likely(x) __builtin_expect((x),1)</span>
<span style="color: #0000dd;">14</span><span style="color: #339933;">:</span> <span style="color: #339933;">#define unlikely(x) __builtin_expect((x),0)</span>
<span style="color: #339933;">++++</span> kernel<span style="color: #339933;">/</span>sched.<span style="color: #202020;">c</span>
<span style="color: #0000dd;">564</span><span style="color: #339933;">:</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>unlikely<span style="color: #009900;">&#40;</span>in_interrupt<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<span style="color: #0000dd;">565</span><span style="color: #339933;">:</span> printk<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Scheduling in interrupt<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #0000dd;">566</span><span style="color: #339933;">:</span> BUG<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #0000dd;">567</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>这个内建函数的语义是 EXP 的预期值是 C，编译器可以根据这个信息适当地重排语句块的顺序，使程序在预期的情况下有更高的执行效率。上面的例子表示处于中断上下文是很少发生的，第 565-566 行的目标码可能会放在较远的位置，以保证经常执行的目标码更紧凑。 ﻿</p>
]]></content:encoded>
			<wfw:commentRss>http://zhuwenhao.com/387/%e6%8a%80%e6%9c%af/%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e8%af%ad%e8%a8%80/c-%e8%af%ad%e8%a8%80/gcc%e6%89%a9%e5%b1%95%ef%bc%8c%e5%9c%a8linux-kernel%e4%b8%ad%e7%9a%84%e4%bd%bf%e7%94%a8%e7%a4%ba%e4%be%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>程序员修炼之路－C语言</title>
		<link>http://zhuwenhao.com/375/%e6%8a%80%e6%9c%af/%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e8%af%ad%e8%a8%80/c-%e8%af%ad%e8%a8%80/%e7%a8%8b%e5%ba%8f%e5%91%98%e4%bf%ae%e7%82%bc%e4%b9%8b%e8%b7%af%ef%bc%8dc%e8%af%ad%e8%a8%80/</link>
		<comments>http://zhuwenhao.com/375/%e6%8a%80%e6%9c%af/%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e8%af%ad%e8%a8%80/c-%e8%af%ad%e8%a8%80/%e7%a8%8b%e5%ba%8f%e5%91%98%e4%bf%ae%e7%82%bc%e4%b9%8b%e8%b7%af%ef%bc%8dc%e8%af%ad%e8%a8%80/#comments</comments>
		<pubDate>Sun, 09 May 2010 12:50:59 +0000</pubDate>
		<dc:creator>朱文昊 Albert Zhu</dc:creator>
				<category><![CDATA[C 语言]]></category>
		<category><![CDATA[构造]]></category>

		<guid isPermaLink="false">http://zhuwenhao.com/?p=375</guid>
		<description><![CDATA[在程序员修炼之路这个系列里面，转载过几篇他人的文章。最近有同学问我如何深入学习C语言和职业规划的问题，让我决心自己动手总结一些观点，和朋友共勉。于是就有了这篇同名文章。
要想成为一名合格的C语言程序员，读什么样的书是一个首先碰到的基本问题。我的品位是，读计算机方面的著作，一定要读国外人写的经典级别的书。回忆我的往事，在中学时候看了一点BASIC基础，学会了盲打，会用了Windows  [...]]]></description>
			<content:encoded><![CDATA[<p>在程序员修炼之路这个系列里面，转载过几篇他人的文章。最近有同学问我如何深入学习C语言和职业规划的问题，让我决心自己动手总结一些观点，和朋友共勉。于是就有了这篇同名文章。</p>
<p>要想成为一名合格的C语言程序员，读什么样的书是一个首先碰到的基本问题。我的品位是，读计算机方面的著作，一定要读国外人写的经典级别的书。回忆我的往事，在中学时候看了一点BASIC基础，学会了盲打，会用了Windows 3X和95，这些就是我在读大学前全部的计算机基础知识。在大学第一年的寒假，回家的火车上，我没有买到座位票，于是只好站着回家。在这十八个小时的旅途中，我阅读了大约1/2的《C程序设计语言》，对，就是那本Kernighan和Richie合著的薄薄的书。不过惭愧的是，我当时的英语很差，读的当然是东南大学徐宝文翻译的第一版。徐先生的翻译很好，所以我才能顺利读下来。有人可能觉得奇怪，没有什么基础的情况下，如何能读完这么一本书？我的感受是，当要学习一种全新的东西，读书不能奢望全理解，勇敢的看下去，看完它，和作者的第一次沟通才能完成。</p>
<p>这第一次沟通，奠定了我的C语言基础知识，也决定了我今后在C语言程序员、系统软件设计、嵌入式系统设计等方面的职业脉络。读了第一本C语言经典之后，应该就可以编写一些和书中例程差不多的小程序了。接下来需要阅读的经典有：《C专家编程》(Expert C Programming &#8212; Deep C Secrets)、《C陷阱与缺陷》(C Traps and Pitfalls)、《C和指针》(Pointers on C)、《C语言核心技术》(C in a Nutshell)、《代码大全》(Code Complete)。读完了这些书，基本上就可以号称是C语言程序员了。</p>
<p>其中《C和指针》我接触的比较晚，非常的遗憾。当我读了《C和指针》，那种相见恨晚的感觉，难于言表。《C专家编程》《C陷阱与缺陷》这两本书，作者处的时代很久远了。如果在现代PC程序设计领域，相关问题可能很少遇到。但是对C语言程序员而言，还是要继续列为必读书目，因为那些晦涩的问题，还是会不停的重现在嵌入式系统的硬件和编译环境里。《代码大全》结合一定的工作经验来读，会有更深的感触。</p>
<p>学习C语言的路还没有结束，真的要理解C语言，你就要了解“语言”，读一读《程学设计语言》(Programming Language-Michael L. Scott)吧。这本研究生和本科课程通用的教材，会让你对C语言的了解上升一个层次，不，一个数量级。</p>
<p>过了这个界线，C语言的学习就该依据职业规划来细分道路了。我只能根据自己的经验谈谈。</p>
<p>首先，学会用Linux操作体系或者其他类似的＊nix系统，因为这些系统是面向程序员的操作系统，如果你真的是一个程序员，在＊nix你会感到更舒服。会用Gcc也是必须的。</p>
<p>其次，读一下Intel出版的《多核程序设计》。</p>
<p>(本文未完成，请期待更新)</p>
]]></content:encoded>
			<wfw:commentRss>http://zhuwenhao.com/375/%e6%8a%80%e6%9c%af/%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e8%af%ad%e8%a8%80/c-%e8%af%ad%e8%a8%80/%e7%a8%8b%e5%ba%8f%e5%91%98%e4%bf%ae%e7%82%bc%e4%b9%8b%e8%b7%af%ef%bc%8dc%e8%af%ad%e8%a8%80/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<series:name><![CDATA[程序员修炼之路]]></series:name>
	</item>
	</channel>
</rss>

