<?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/"
	>

<channel>
	<title>Dutor &#187; 边走编程</title>
	<atom:link href="http://www.dutor.net/index.php/category/program/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dutor.net</link>
	<description>熟读而精思，循序而渐进，厚积而薄发。</description>
	<lastBuildDate>Tue, 17 Jan 2012 14:44:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>[C++]对象中使用pthread线程</title>
		<link>http://www.dutor.net/index.php/2011/11/pthread-in-cpp-class/</link>
		<comments>http://www.dutor.net/index.php/2011/11/pthread-in-cpp-class/#comments</comments>
		<pubDate>Fri, 18 Nov 2011 08:50:37 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[Cpp]]></category>
		<category><![CDATA[pthread]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2671</guid>
		<description><![CDATA[　　我们还知道，类的静态成员函数是不需要绑定到特定对象上面的，所以我们就可以将worker声明为静态成员。
<pre lang="cpp" line="1">
class Thread
{
public:
    static void* worker(void* args) {
        //~ thread execution.
    }
private:
    //~ here some data member.
};
pthread_t tid;
pthread_create(&#038;tid, NULL, &#038;Thread::worker, NULL);
</pre>
　　我们又知道，静态成岩函数是不能'直接'访问类的非静态成员（包括函数），因此，上面代码中worker即使属于class Thread的类域，但却无法访问这个类的成员，这让人十分不爽。哪位大牛说过来着？任何一个复杂的计算机问题，都可以通过中间层来解决。这里也可以建立一个中间层：使用静态成员函数创建线程，给该函数传递某个对象的地址作为参数，在该静态函数中就可以通过所传递对象的使用它的任何成员了。]]></description>
			<content:encoded><![CDATA[<p>pthread中使用pthread_create创建线程：</p>

<div class="wp_codebox"><table><tr id="p26711"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code" id="p2671code1"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> worker<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>args<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #666666;">//~ thread execution.</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">NULL</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
pthread_t tid<span style="color: #008080;">;</span>
<span style="color: #666666;">//~ pthread_create(pthread_t*, pthread_attr_t*, void*(*)(void*), void*);</span>
pthread_create<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>tid, <span style="color: #0000ff;">NULL</span>, worker, <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>　　其中，线程函数worker就是所创建线程将要执行的代码。当然，由于同一进程中各线程的代码段是共享的，所以在线程函数中可以像普通函数那样合法地调用其他函数。<br />
　　有时候，我们可能想要将一个类的成员函数作为一个单独的线程来执行，甚至在某个类中控制线程的执行。但我们并不能直接使用成员函数来创建线程，像下面一样，</p>

<div class="wp_codebox"><table><tr id="p26712"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code" id="p2671code2"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">class</span> Thread
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> worker<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> args<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #666666;">//~ thread execution.</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    <span style="color: #666666;">//~ here some data member.</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
pthread_t tid<span style="color: #008080;">;</span>
pthread_create<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>tid, <span style="color: #0000ff;">NULL</span>, <span style="color: #000040;">&amp;</span>Thread<span style="color: #008080;">::</span><span style="color: #007788;">worker</span>, <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>　　编译上面代码，会得到类似</p>
<pre>
error: cannot convert ‘void* (Thread::*)(void*)’ to ‘void* (*)(void*)’ for argument ‘3’ to
‘int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)’
</pre>
<p>的错误信息，意思是说，对于pthread_create的第三个参数，无法将void* (Thread::*)(void*)转化为void* (*)(void*)类型。我们知道，类的普通成员函数的执行是绑定到某一个具体的对象上面的，除了我们声明的参数之外，还需要一个&#8217;多余&#8217;的参数this来指明该函数的本次执行所绑定到的对象。<br />
　　我们还知道，类的静态成员函数是不需要绑定到特定对象上面的，所以我们就可以将worker声明为静态成员。</p>

<div class="wp_codebox"><table><tr id="p26713"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code" id="p2671code3"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">class</span> Thread
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> worker<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> args<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #666666;">//~ thread execution.</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    <span style="color: #666666;">//~ here some data member.</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
pthread_t tid<span style="color: #008080;">;</span>
pthread_create<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>tid, <span style="color: #0000ff;">NULL</span>, <span style="color: #000040;">&amp;</span>Thread<span style="color: #008080;">::</span><span style="color: #007788;">worker</span>, <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>　　我们又知道，静态成岩函数是不能&#8217;直接&#8217;访问类的非静态成员（包括函数），因此，上面代码中worker即使属于class Thread的类域，但却无法访问这个类的成员，这让人十分不爽。哪位大牛说过来着？任何一个复杂的计算机问题，都可以通过中间层来解决。这里也可以建立一个中间层：使用静态成员函数创建线程，给该函数传递某个对象的地址作为参数，在该静态函数中就可以通过所传递对象的使用它的任何成员了。<br />
　　我比较喜欢使用的是类似这样的一个抽象类，</p>

<div class="wp_codebox"><table><tr id="p26714"><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="p2671code4"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">class</span> Thread
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">virtual</span> ~Thread<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
    pthread_t start<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        pthread_t tid<span style="color: #008080;">;</span>
        pthread_create<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>tid, <span style="color: #0000ff;">NULL</span>, hook, <span style="color: #0000dd;">this</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">return</span> tid<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> hook<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> args<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">reinterpret_cast</span><span style="color: #000080;">&lt;</span>Thread<span style="color: #000040;">*</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span>args<span style="color: #008000;">&#41;</span><span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>worker<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">NULL</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">protected</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> worker<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>继承这个类，实现worker函数就行了。调用start启动线程，各线程共享对象的数据。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2011/11/pthread-in-cpp-class/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于变参</title>
		<link>http://www.dutor.net/index.php/2011/08/variadic/</link>
		<comments>http://www.dutor.net/index.php/2011/08/variadic/#comments</comments>
		<pubDate>Sun, 07 Aug 2011 02:32:20 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[Cpp]]></category>
		<category><![CDATA[可变参数]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2626</guid>
		<description><![CDATA[<h4>使用变参</h4>
　　C/C++提供了函数的可变参数(variadic)机制，大部分人写的第一个C程序恐怕就是Hello World吧，使用的应该也是printf("Hello, World\n")。printf就是一个使用可变参数的典型，它的原型声明为，
<pre lang="C">
int printf(const char *fmt, ...);
</pre>
　　其中返回值为实际输出字符个数，fmt为格式控制字符串，而"..."便声明了一个可变参数，你可以根据传递0个或多个参数给printf。printf内部会根据格式控制串中的格式指定符号（d, f, p等等）来逐个解析通过可变参数传进的实参变量。
　　为解析可变参数，C语言提供了一个va_list类型和四个宏，分别是va_start, va_arg, va_end, 和va_copy，这些宏声明在stdarg.h中。]]></description>
			<content:encoded><![CDATA[<h4>使用变参</h4>
<p>　　C/C++提供了函数的可变参数(variadic)机制，大部分人写的第一个C程序恐怕就是Hello World吧，使用的应该也是printf(&#8220;Hello, World\n&#8221;)。printf就是一个使用可变参数的典型，它的原型声明为，</p>

<div class="wp_codebox"><table><tr id="p26265"><td class="code" id="p2626code5"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> <span style="color: #000066;">printf</span><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: #339933;">;</span></pre></td></tr></table></div>

<p>　　其中返回值为实际输出字符个数，fmt为格式控制字符串，而&#8221;&#8230;&#8221;便声明了一个可变参数，你可以根据传递0个或多个参数给printf。printf内部会根据格式控制串中的格式指定符号（d, f, p等等）来逐个解析通过可变参数传进的实参变量。<br />
　　为解析可变参数，C语言提供了一个va_list类型和四个宏，分别是va_start, va_arg, va_end, 和va_copy，这些宏声明在stdarg.h中。为了方便描述，下面实现一个简单的类似printf的函数：</p>

<div class="wp_codebox"><table><tr id="p26266"><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
34
35
</pre></td><td class="code" id="p2626code6"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> mockprintf<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: #009900;">&#123;</span>
    va_list ap<span style="color: #339933;">;</span>
    va_start<span style="color: #009900;">&#40;</span>ap<span style="color: #339933;">,</span> fmt<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>s <span style="color: #339933;">=</span> fmt<span style="color: #339933;">;</span> <span style="color: #339933;">*</span>s<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>s<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">switch</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>s<span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #b1b100;">case</span> <span style="color: #ff0000;">'d'</span><span style="color: #339933;">:</span>
                <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;meet d<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: #993333;">int</span> d <span style="color: #339933;">=</span> va_arg<span style="color: #009900;">&#40;</span>ap<span style="color: #339933;">,</span> <span style="color: #993333;">int</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #000066;">printf</span><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> d<span style="color: #009900;">&#41;</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;">'s'</span><span style="color: #339933;">:</span>
                <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;meet s<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: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>str <span style="color: #339933;">=</span> va_arg<span style="color: #009900;">&#40;</span>ap<span style="color: #339933;">,</span> <span style="color: #993333;">char</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> str<span style="color: #009900;">&#41;</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;">'c'</span><span style="color: #339933;">:</span>
                <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;meet c<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: #993333;">char</span> c <span style="color: #339933;">=</span> va_arg<span style="color: #009900;">&#40;</span>ap<span style="color: #339933;">,</span> <span style="color: #993333;">int</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%c<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>
                <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">default</span><span style="color: #339933;">:</span>
                <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;unknown format specifier<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: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    va_end<span style="color: #009900;">&#40;</span>ap<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #993333;">int</span>
main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    mockprintf<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;cdfs&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">'A'</span><span style="color: #339933;">,</span> <span style="color: #208080;">0x45</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;string&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>　　va_list的实现与编译器和平台相关，通常是一个指向参数栈的指针。va_start使用变参列表前的最后一个命名参数（named argument）作为参数，以此定位变参列表的第一个参数的地址，并将ap指向该参数（此处假设va_list实现为指针）。宏va_arg需要两个参数，va_list变量和下一个预期的参数的类型，该宏以指定类型返回（展开为）对应的参数值，并调整va_list指向下一个参数。最后，每一个va_start需要一个va_end作为结束。另外，示例函数中没有用到va_copy，这是一个用来复制va_list变量到另一个va_list变量的宏，目的是应对平台间va_list实现的差异。<br />
　　值得一提的是，va_start和va_end可以重复调用，用以多次对变参列表进行解析。</p>
<h4>printf家族</h4>
<p>　　C的printf家族包含8个成员，原型如下，</p>

<div class="wp_codebox"><table><tr id="p26267"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code" id="p2626code7"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
<span style="color: #993333;">int</span> <span style="color: #000066;">printf</span><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: #339933;">;</span>
<span style="color: #993333;">int</span> fprintf<span style="color: #009900;">&#40;</span>FILE <span style="color: #339933;">*</span>stream<span style="color: #339933;">,</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: #339933;">;</span>
<span style="color: #993333;">int</span> sprintf<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>str<span style="color: #339933;">,</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: #339933;">;</span>
<span style="color: #993333;">int</span> snprintf<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>str<span style="color: #339933;">,</span> size_t size<span style="color: #339933;">,</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: #339933;">;</span>
&nbsp;
<span style="color: #339933;">#include &lt;stdarg.h&gt;</span>
<span style="color: #993333;">int</span> vprintf<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> va_list ap<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">int</span> vfprintf<span style="color: #009900;">&#40;</span>FILE <span style="color: #339933;">*</span>stream<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>fmt<span style="color: #339933;">,</span> va_list ap<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">int</span> vsprintf<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>str<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>fmt<span style="color: #339933;">,</span> va_list ap<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">int</span> vsnprintf<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span>str<span style="color: #339933;">,</span> size_t size<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>fmt<span style="color: #339933;">,</span> va_list ap<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>　　前四个函数没有什么特殊的。后面四个v系列可以接受va_list变量，通常用在对可变参数输出的包装，在日志记录系统中较为常用。比如下面代码，</p>

<div class="wp_codebox"><table><tr id="p26268"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code" id="p2626code8"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">enum</span> LogLevel <span style="color: #008000;">&#123;</span> ERROR, WARN, INFO, DEBUG <span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">void</span> <span style="color: #0000dd;">log</span><span style="color: #008000;">&#40;</span>LogLevel level, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>fmt, ...<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">va_list</span> ap<span style="color: #008080;">;</span>
    <span style="color: #0000dd;">va_start</span><span style="color: #008000;">&#40;</span>ap, fmt<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    vsnprintf<span style="color: #008000;">&#40;</span>buf, <span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>buf<span style="color: #008000;">&#41;</span>, fmt, ap<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">va_end</span><span style="color: #008000;">&#40;</span>ap<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #666666;">//~ write buf to file, or do something else.</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　v系列函数并不会调用va_end宏，因此在这些函数返回后，需要调用函数自己进行va_end。若要再次解析变参列表，就需要重新va_start, va_end。</p>
<h4>宏变参</h4>
<p>　　除了函数，在C/C++中，带参宏定义也可以接受变参，使用方法和函数类似。比如，若将上面的log函数的某个级别的日志输入定义成宏，</p>

<div class="wp_codebox"><table><tr id="p26269"><td class="code" id="p2626code9"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#define log_warn(fmt, ...) log(WARN, fmt, __VA_ARGS__)</span></pre></td></tr></table></div>

<p>　　__VA_ARGS__只是被预处理器简单的展开为传递给宏log_warn的变参列表，包括逗号分隔符。若想使用具有鲜明意义的名字，而不是统一的__VA_ARGS__，可以这样，</p>

<div class="wp_codebox"><table><tr id="p262610"><td class="code" id="p2626code10"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#define log_warn(fmt, args...) log(WARN, fmt, args)</span></pre></td></tr></table></div>

<p>　　上述宏定义中，有一个问题值得注意，就是当变参列表为空时，log函数调用的参数列表会有一个结尾的逗号，这在某些编译器中会被诊断为错误（据说MSVC不会），这种情况下可以将fmt也纳入变参列表，</p>

<div class="wp_codebox"><table><tr id="p262611"><td class="code" id="p2626code11"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#define log_warn(...) log(WARN, __VA_ARGS__)</span></pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2011/08/variadic/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>几道百度面试题目</title>
		<link>http://www.dutor.net/index.php/2011/05/interviews-from-baidu/</link>
		<comments>http://www.dutor.net/index.php/2011/05/interviews-from-baidu/#comments</comments>
		<pubDate>Wed, 25 May 2011 11:14:48 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[边走编程]]></category>
		<category><![CDATA[面试题]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2592</guid>
		<description><![CDATA[　　参加了三次百度公司的面试，遇到了些面试题，根据记忆，列到这里，如果你对某些题有想法，不妨回复讨论一下。

<ol>
	<li> 谈一下static关键词，C&#038;C++：<span style="color: #FF0000;">文件域，函数域，类域</span> </li>
	<li> 说说<a href="http://www.dutor.net/index.php/2010/08/volatile-const/" target="_blank">volatile</a> </li>
	<li> static成员（变量/函数，尤其是变量）需要注意哪些问题：<span style="color: #FF0000;">static变量需在类外，通常为.cpp文件中显式声明，否则会有链接错误</span> </li>
	<li> STL由哪些部件组成：<span style="color: #FF0000;">容器，迭代器，算法，仿函数，各类适配器等等</span> </li>
	<li> STL标准容器有哪些，特性是什么：<span style="color: #FF0000;">vector，deque, list, map/multimap, set/multiset</span> </li>
	<li> vector的插入操作过程中会发生什么：<span style="color: #FF0000;">内存分配/重分配/释放，元素构造/析构……</span> </li>
	<li> 谈谈对适配容器的理解：<span style="color: #FF0000;">stack, queue, priority_queue，对标准容器的适配/封装</span> </li>
	<li> 谈谈C++ </li>
	<li> 进程间通讯有哪些方式：<span style="color: #FF0000;">内存共享，socket（包括Unix Domain），消息</span> </li>
	<li> 两相同行数文件，每行一列，使用awk按列合并之： <span style="color: #FF0000;">awk '{t = $1; getline <"file2"; print t, $1}' file2</span> </li>
	<li> 你该如何实现tail命令：<span style="color: #FF0000;">lseek, read, write....</span> </li>
	<li> 实现atoi：<span style="color: #FF0000;">指针有效性，字符有效性，整数溢出，错误状态</span> </li>
	<li> memcpy与memmove有何区别：<span style="color: #FF0000;">overlap</span> </li>
	<li> 列出你所知道的排序方法及其复杂度、稳定性和适用情形 </li>
	<li> <a href="http://www.dutor.net/index.php/2011/04/recursive-iterative-quick-sort/" target="_blank">非递归实现快速排序</a> </li>
	<li> 快速排序的复杂度证明 </li>
	<li> 非递归实现二叉树的后续遍历 </li>
	<li> 判断单链表是否存在环，环从何开始：<span style="color: #FF0000;">老题了</span> </li>
	<li> 仅知道单链表中某非尾节点的地址，O(1)删除该节点：<span style="color: #FF0000;">节点覆盖</span> </li>
	<li> 某文件大小为10G，每行保存一个整数，内存不可完全容纳，排序之：<span style="color: #FF0000;">分段排序，然后败者树归并</span> </li>
	<li> 简单描述<a href="http://www.dutor.net/index.php/2010/04/virtual-memory/" target="_blank">虚拟内存</a>机制 </li>
	<li> 简单描述Linux进程模型（即包含哪些段，作用是什么，有何特性） </li>
	<li> 软、硬链接有何区别 </li>
	<li> 一个系统，维护id->value的信息，信息量巨大，需多台服务器存储。系统可支持信息的增、删、改、查询及批量查询，每日增删该约千万次，查询约10亿次。设计该系统</li>
</ol>
]]></description>
			<content:encoded><![CDATA[<p>　　参加了三次百度公司的面试，遇到了些面试题，根据记忆，列到这里，如果你对某些题有想法，不妨回复讨论一下。</p>
<ol>
<li> 谈一下static关键词，C&#038;C++：<span style="color: #FF0000;">文件域，函数域，类域</span> </li>
<li> 说说<a href="http://www.dutor.net/index.php/2010/08/volatile-const/" target="_blank">volatile</a> </li>
<li> static成员（变量/函数，尤其是变量）需要注意哪些问题：<span style="color: #FF0000;">static变量需在类外，通常为.cpp文件中显式声明，否则会有链接错误</span> </li>
<li> STL由哪些部件组成：<span style="color: #FF0000;">容器，迭代器，算法，仿函数，各类适配器等等</span> </li>
<li> STL标准容器有哪些，特性是什么：<span style="color: #FF0000;">vector，deque, list, map/multimap, set/multiset</span> </li>
<li> vector的插入操作过程中会发生什么：<span style="color: #FF0000;">内存分配/重分配/释放，元素构造/析构……</span> </li>
<li> 谈谈对适配容器的理解：<span style="color: #FF0000;">stack, queue, priority_queue，对标准容器的适配/封装</span> </li>
<li> 谈谈C++ </li>
<li> 进程间通讯有哪些方式：<span style="color: #FF0000;">内存共享，socket（包括Unix Domain），消息</span> </li>
<li> 两相同行数文件，每行一列，使用awk按列合并之： <span style="color: #FF0000;">awk &#8216;{t = $1; getline <"file2"; print t, $1}' file2</span> </li>
<li> 你该如何实现tail命令：<span style="color: #FF0000;">lseek, read, write&#8230;.</span> </li>
<li> 实现atoi：<span style="color: #FF0000;">指针有效性，字符有效性，整数溢出，错误状态</span> </li>
<li> memcpy与memmove有何区别：<span style="color: #FF0000;">overlap</span> </li>
<li> 列出你所知道的排序方法及其复杂度、稳定性和适用情形 </li>
<li> <a href="http://www.dutor.net/index.php/2011/04/recursive-iterative-quick-sort/" target="_blank">非递归实现快速排序</a> </li>
<li> 快速排序的复杂度证明 </li>
<li> 非递归实现二叉树的后续遍历 </li>
<li> 判断单链表是否存在环，环从何开始：<span style="color: #FF0000;">老题了</span> </li>
<li> 仅知道单链表中某非尾节点的地址，O(1)删除该节点：<span style="color: #FF0000;">节点覆盖</span> </li>
<li> 某文件大小为10G，每行保存一个整数，内存不可完全容纳，排序之：<span style="color: #FF0000;">分段排序，然后败者树归并</span> </li>
<li> 简单描述<a href="http://www.dutor.net/index.php/2010/04/virtual-memory/" target="_blank">虚拟内存</a>机制 </li>
<li> 简单描述Linux进程模型（即包含哪些段，作用是什么，有何特性） </li>
<li> 软、硬链接有何区别 </li>
<li> 一个系统，维护id->value的信息，信息量巨大，需多台服务器存储。系统可支持信息的增、删、改、查询及批量查询，每日增删该约千万次，查询约10亿次。设计该系统</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2011/05/interviews-from-baidu/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>[C++]对虚函数的一次把玩</title>
		<link>http://www.dutor.net/index.php/2011/05/stuff-about-vptr-vtbl/</link>
		<comments>http://www.dutor.net/index.php/2011/05/stuff-about-vptr-vtbl/#comments</comments>
		<pubDate>Thu, 05 May 2011 16:01:30 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[Cpp]]></category>
		<category><![CDATA[虚函数]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2583</guid>
		<description><![CDATA[　　关于虚函数，需要知道：

<ul>
	<li> 多态在C++中借助虚函数实现 </li>
	<li> 多态只在指针或者引用上发生 </li>
	<li> 虚函数机制（通常）借助虚指针vptr支持 </li>
	<li> 虚函数地址保存在虚函数表中 </li>
	<li> 一个类的所有对象共有一张vtbl </li>
	<li> vtbl由vptr指向，vptr保存在每一个对象中，多继承时可能有多个vptr </li>
	<li> vptr由构造函数（普通构造/copy构造）在对象初始化时隐式设定 </li>
</ul>]]></description>
			<content:encoded><![CDATA[<p>以下代码，</p>

<div class="wp_codebox"><table><tr id="p258312"><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
</pre></td><td class="code" id="p2583code12"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">class</span> B
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    B<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
    B<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> B<span style="color: #000040;">&amp;</span> b<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000dd;">memcpy</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">this</span>, <span style="color: #000040;">&amp;</span>b, <span style="color: #0000dd;">sizeof</span> b<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> foo<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;B::foo()&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">class</span> D<span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> B
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> foo<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;D::foo()&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">void</span> bar<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> B<span style="color: #000040;">&amp;</span> b<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    b.<span style="color: #007788;">foo</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　类D继承自类B，并重写了virtual函数foo()。特殊的是B的copy构造函数，它将参数b按位copy到自身。由于B中没有任何数据成员（除了vptr，即虚函数表指针），如果b所关联的就是一个B对象，这没有任何问题。但b还以关联到B的子类，这时问题就来了，因为此时由copy构造出的对象的vptr指向的并不是B的vtbl（虚函数表），而是指向b实际类型的vtbl。</p>

<div class="wp_codebox"><table><tr id="p258313"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code" id="p2583code13"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    D d<span style="color: #008080;">;</span>
    B b <span style="color: #000080;">=</span> d<span style="color: #008080;">;</span>
    B <span style="color: #000040;">&amp;</span>r <span style="color: #000080;">=</span> b<span style="color: #008080;">;</span>
    r.<span style="color: #007788;">foo</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　执行这个代码片段，会输出什么？<br />
　　出乎意料，输出的仍然是B::foo()。可是为什么呢？使用GDB调试，</p>
<pre>
(gdb) x/xg &#038;d
0x7fffffffe000: 0x0000000000400bf0
(gdb) x/xg &#038;b
0x7fffffffdff0: 0x0000000000400bf0
(gdb) x/xg &#038;r
0x7fffffffdff0: 0x0000000000400bf0
(gdb)
</pre>
<p>　　发现b的vptr确实是和d相同。但r.foo()调用了B::foo()，唯一的解释就是，编译器看穿了我的伎俩，发现我是在一个b“对象”上面调用的虚函数，并没有使用vptr/vtbl调用foo，绕过了虚函数机制直接调用了B::foo()。有汇编为证，</p>
<pre>
   0x000000000040098c <+39>:    lea    -0x20(%rbp),%rax # 取b地址
   0x0000000000400990 <+43>:    mov    %rax,-0x28(%rbp) # 赋给r
   0x0000000000400994 <+47>:    mov    -0x28(%rbp),%rax
   0x0000000000400998 <+51>:    mov    %rax,%rdi # 以%rdi寄存器传递this
=> 0x000000000040099b <+54>:    callq  0x400a54 <B::foo() const>#调用B::foo()
</pre>
<p>　　吼吼，编译器知道的太多啦！咱们换种策略，</p>

<div class="wp_codebox"><table><tr id="p258314"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code" id="p2583code14"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span> bar<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> B<span style="color: #000040;">&amp;</span> b<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    b.<span style="color: #007788;">foo</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    D d<span style="color: #008080;">;</span>
    B b <span style="color: #000080;">=</span> d<span style="color: #008080;">;</span> <span style="color: #666666;">//~ 调用B::B(const B&amp; b)</span>
    bar<span style="color: #008000;">&#40;</span>b<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>    嗯，这把行了，不信还看汇编，</p>
<pre>
Dump of assembler code for function main():
    ...
=> 0x000000000040098c <+39>:    lea    -0x20(%rbp),%rax #取b地址
   0x0000000000400990 <+43>:    mov    %rax,%rdi # 赋予%rdi
   0x0000000000400993 <+46>:    callq  0x400944 <bar(B const&#038;)>#调用bar
    ...
Dump of assembler code for function bar(B const&#038;):
    ...
   0x000000000040094c <+8>:     mov    %rdi,-0x8(%rbp) #获取&#038;b
   0x0000000000400950 <+12>:    mov    -0x8(%rbp),%rax
   0x0000000000400954 <+16>:    mov    (%rax),%rax # 获取vptr
   0x0000000000400957 <+19>:    mov    (%rax),%rdx # 获取foo地址
   0x000000000040095a <+22>:    mov    -0x8(%rbp),%rax #获取&#038;b
   0x000000000040095e <+26>:    mov    %rax,%rdi # 传递this
   0x0000000000400961 <+29>:    callq  *%rdx # 调用D::foo()
</pre>
<p>　　关于虚函数，需要知道：</p>
<ul>
<li> 多态在C++中借助虚函数实现 </li>
<li> 多态只在指针或者引用上发生 </li>
<li> 虚函数机制（通常）借助虚指针vptr支持 </li>
<li> 虚函数地址保存在虚函数表中 </li>
<li> 一个类的所有对象共有一张vtbl </li>
<li> vtbl由vptr指向，vptr保存在每一个对象中，多继承时可能有多个vptr </li>
<li> vptr由构造函数（普通构造/copy构造）在对象初始化时隐式设定 </li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2011/05/stuff-about-vptr-vtbl/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>迭代版快速排序</title>
		<link>http://www.dutor.net/index.php/2011/04/recursive-iterative-quick-sort/</link>
		<comments>http://www.dutor.net/index.php/2011/04/recursive-iterative-quick-sort/#comments</comments>
		<pubDate>Fri, 29 Apr 2011 08:43:54 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之算法神奇]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[排序]]></category>
		<category><![CDATA[迭代]]></category>
		<category><![CDATA[递归]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2575</guid>
		<description><![CDATA[　　递归是一种使用相同的方法，通过解决问题的子集以达到解决整个问题的方法，是一种使用有限代码解决“无限”计算的方法。在C/C++语言中递归表现在函数对自身的直接/间接的调用上，在实现上，递归依赖于语言的运行时调用堆栈，使用堆栈来保存每一次递归调用返回时所需要的条件。递归通常具有简洁的编码和清晰的思路，但这种简洁是有代价的。一方面，是函数调用的负担；另一方面，是堆栈占用的负担（堆栈的大小是有限的）。
　　避免这种负担的方法就是将递归转化为迭代。迭代的思想主要在于，在同一栈帧中不断使用现有数据计算出新的数据，然后使用新的数据来替换原有数据。递归于迭代可以相互转化。将递归转化为迭代需要做两方面的工作：显式地维护一个堆栈，在递归算法中堆栈的维护由编译器隐式地完成；使用迭代控制结构，完成出栈、入栈和相关的计算。]]></description>
			<content:encoded><![CDATA[<p>　　递归是一种使用相同的方法，通过解决问题的子集以达到解决整个问题的方法，是一种使用有限代码解决“无限”计算的方法。在C/C++语言中递归表现在函数对自身的直接/间接的调用上，在实现上，递归依赖于语言的运行时调用堆栈，使用堆栈来保存每一次递归调用返回时所需要的条件。递归通常具有简洁的编码和清晰的思路，但这种简洁是有代价的。一方面，是函数调用的负担；另一方面，是堆栈占用的负担（堆栈的大小是有限的）。<br />
　　避免这种负担的方法就是将递归转化为迭代。迭代的思想主要在于，在同一栈帧中不断使用现有数据计算出新的数据，然后使用新的数据来替换原有数据。递归于迭代可以相互转化。将递归转化为迭代需要做两方面的工作：显式地维护一个堆栈，在递归算法中堆栈的维护由编译器隐式地完成；使用迭代控制结构，完成出栈、入栈和相关的计算。<br />
　　以快速排序为例，递归版本的快排通常是这个样子的，</p>

<div class="wp_codebox"><table><tr id="p257515"><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
</pre></td><td class="code" id="p2575code15"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span>
partition<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> <span style="color: #339933;">*</span>a<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> n<span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//~ seperate a[], using a[0] as pivot</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> l <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> r <span style="color: #339933;">=</span> n<span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> pivot <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>l<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>l <span style="color: #339933;">&lt;</span> r<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span> l <span style="color: #339933;">&lt;</span> r <span style="color: #339933;">&amp;&amp;</span> a<span style="color: #009900;">&#91;</span><span style="color: #339933;">--</span>r<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&gt;</span> pivot<span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
        a<span style="color: #009900;">&#91;</span>l<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>r<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>l <span style="color: #339933;">&lt;</span> r <span style="color: #339933;">&amp;&amp;</span> a<span style="color: #009900;">&#91;</span><span style="color: #339933;">++</span>l<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&lt;</span> pivot<span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
        a<span style="color: #009900;">&#91;</span>r<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>l<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    a<span style="color: #009900;">&#91;</span>l<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> pivot<span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> l<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//~ return the final index of pivot</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #993333;">void</span>
qsort_recur<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> <span style="color: #339933;">*</span>a<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> n<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>n <span style="color: #339933;">&lt;=</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>
        <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> m <span style="color: #339933;">=</span> partition<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>m <span style="color: #339933;">&lt;=</span> n <span style="color: #339933;">/</span> <span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        qsort_recur<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> m<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        qsort_recur<span style="color: #009900;">&#40;</span>a <span style="color: #339933;">+</span> m <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> n <span style="color: #339933;">-</span> m <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">else</span>
    <span style="color: #009900;">&#123;</span>
        qsort_recur<span style="color: #009900;">&#40;</span>a <span style="color: #339933;">+</span> m <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> n <span style="color: #339933;">-</span> m <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        qsort_recur<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> m<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>　　为了将递归排序转化为迭代排序，首先要做的就是考察需要将哪些变量保存到堆栈，这些变量何时入栈何时出栈，需要做什么计算，迭代的终止条件是什么。<br />
　　根据快速排序的核心思想（分而治之），所需要的做的“计算”就是将“区间”按照某个支点（比如区间第一个元素）分为两个子区间，然后再分别对两个子区间进行相同的操作。可见，我们需要在栈中维护的信息就是“区间”，因为在对一个区间进行“计算”时，其他区间信息需要保存。这样才能在处理完当前区间的工作之后继续处理其他区间。迭代的终止条件是什么？所有的区间都处理完了。<br />
　　下面是迭代版本的快速排序，</p>

<div class="wp_codebox"><table><tr id="p257516"><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="p2575code16"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span>
qsort_iter<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span>a, <span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #666666;">//~ qsort of 'iterative version</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>n <span style="color: #000080;">&lt;=</span> <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span>
        <span style="color: #0000ff;">return</span> <span style="color: #008080;">;</span>
    stack<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> ranges<span style="color: #008080;">;</span> <span style="color: #666666;">//~ stack of ranges to be sorted</span>
    <span style="color: #0000ff;">int</span> l <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> r <span style="color: #000080;">=</span> n<span style="color: #008080;">;</span>
    ranges.<span style="color: #007788;">push</span><span style="color: #008000;">&#40;</span>l<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//~ initial range</span>
    ranges.<span style="color: #007788;">push</span><span style="color: #008000;">&#40;</span>r<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">while</span><span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>ranges.<span style="color: #007788;">empty</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">int</span> tr <span style="color: #000080;">=</span> r <span style="color: #000080;">=</span> ranges.<span style="color: #007788;">top</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> ranges.<span style="color: #007788;">pop</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">int</span> tl <span style="color: #000080;">=</span> l <span style="color: #000080;">=</span> ranges.<span style="color: #007788;">top</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> ranges.<span style="color: #007788;">pop</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>r <span style="color: #000040;">-</span> l <span style="color: #000080;">&lt;=</span> <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span> <span style="color: #666666;">//~ range sorted</span>
            <span style="color: #0000ff;">continue</span><span style="color: #008080;">;</span>
        <span style="color: #666666;">//~ partition begins</span>
        <span style="color: #0000ff;">int</span> pivot <span style="color: #000080;">=</span> a<span style="color: #008000;">&#91;</span>tl<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">while</span><span style="color: #008000;">&#40;</span>tr <span style="color: #000080;">&gt;</span> tl<span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            <span style="color: #0000ff;">while</span><span style="color: #008000;">&#40;</span>tr <span style="color: #000080;">&gt;</span> tl <span style="color: #000040;">&amp;&amp;</span> a<span style="color: #008000;">&#91;</span><span style="color: #000040;">--</span>tr<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&gt;</span> pivot<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
            a<span style="color: #008000;">&#91;</span>tl<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> a<span style="color: #008000;">&#91;</span>tr<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
            <span style="color: #0000ff;">while</span><span style="color: #008000;">&#40;</span>tr <span style="color: #000080;">&gt;</span> tl <span style="color: #000040;">&amp;&amp;</span> a<span style="color: #008000;">&#91;</span><span style="color: #000040;">++</span>tl<span style="color: #008000;">&#93;</span> <span style="color: #000080;">&lt;</span> pivot<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
            a<span style="color: #008000;">&#91;</span>tr<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> a<span style="color: #008000;">&#91;</span>tl<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
        a<span style="color: #008000;">&#91;</span>tl<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> pivot<span style="color: #008080;">;</span>
        <span style="color: #666666;">//~ partition ends</span>
&nbsp;
        <span style="color: #666666;">//~ ranges pushed, with order counting for little</span>
        ranges.<span style="color: #007788;">push</span><span style="color: #008000;">&#40;</span>l<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> ranges.<span style="color: #007788;">push</span><span style="color: #008000;">&#40;</span>tl<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        ranges.<span style="color: #007788;">push</span><span style="color: #008000;">&#40;</span>tl<span style="color: #000040;">+</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> ranges.<span style="color: #007788;">push</span><span style="color: #008000;">&#40;</span>r<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　代码中，堆栈使用STL的stack适配器，它默认使用deque做底层存储，因此，我们的栈使用的是堆内存，因此你就不必担心stack overflow了。你可能注意到了，这个版本中也使用了不少的函数调用，但都是可以通过自己建立堆栈来消除的。再者，这里只是提供一种思路，相对于迭代的带来的所谓性能“提升”，其带来的复杂性也是不可忽视的。</p>
<p>参考：<a href="http://en.wikipedia.org/wiki/Recursion_(computer_science)#Recursion_versus_iteration" target="_blank">Recursion</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2011/04/recursive-iterative-quick-sort/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>reserve: 对老new的新认识</title>
		<link>http://www.dutor.net/index.php/2011/04/reserve-new-virtual-physical-memory/</link>
		<comments>http://www.dutor.net/index.php/2011/04/reserve-new-virtual-physical-memory/#comments</comments>
		<pubDate>Mon, 25 Apr 2011 13:43:16 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[Cpp]]></category>
		<category><![CDATA[new]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2568</guid>
		<description><![CDATA[　　reserve内部是怎么实现的呢？当然是new了。那么在reserve操作，也就是new之后，我们程序是否立即就占用了这些内存呢？这就要看我们这里说的“内存”是什么样的内存了。什么意思呢？我们知道，现代操作系统都采用了虚拟内存的机制，内存占用也就有了虚拟内存（virtual memory）和物理内存（physical memory）之分了。
　　我们又知道，Unix/Linux进程的虚拟地址空间被按用途被划分成了内核空间和用户空间。内核空间供操作系统的内核使用，用户空间供用户程序支配。其中用户空间又被划分为若干段，主要包括：代码段（.text），用来存放/映射用户程序的代码；数据段（.data），存放初始化的全局数据或静态数据，这部分在文件系统中也占据磁盘空间；.bss段（一直没找到一个亲切的翻译），存放为初始化的全局或静态数据，在程序加载时分配空间和初始化，这部分空间不占用磁盘空间（当然在可执行文件中要保留其大小）；堆栈段，用来保存程序执行时的上下文（局部变量、函数参数和返回地址等），在进程建立时由操作系统分配，空间较小且在运行时不可动态调整，增长方向因机器架构而异，IA上自高地址向下增长，堆栈不占用磁盘空间；堆，供用户在运行时动态地申请和使用，空间较大，未被申请的堆空间不可使用，也不会被映射到物理空间，堆随着用户程序申请向上增长，堆不占用磁盘空间。]]></description>
			<content:encoded><![CDATA[<p>　　C++ STL中的vector&lt;T>是一个变长“数组，在使用push_back等插入操作向vector中添加元素时可以动态地增长其容量(capacity)。然而，这种动态扩容的特性也带来了一定的性能负担。当vector当前容量不足以容纳待插入元素时，vector会另外开辟一段连续的内存，然后将原有元素拷贝(使用元素的copy构造)至新的内存区域，然后释放掉原先占据的内存，特定情况下，这可能是一笔不小的不必要的开销。vector的设计者当然也考虑到这一点，于是提供了reverve(ssize_t)成员函数。顾名思义，reserve为vector预定了一定大小的连续空间，使得在vector元素数量不超过当前容量的插入操作过程中，不会发生拷贝操作，原有迭代器、指针和引用当然也不会失效（insert类操作除外）。</p>
<p>　　reserve内部是怎么实现的呢？当然是new了。那么在reserve操作，也就是new之后，我们程序是否立即就占用了这些内存呢？这就要看我们这里说的“内存”是什么样的内存了。什么意思呢？我们知道，现代操作系统都采用了虚拟内存的机制，内存占用也就有了虚拟内存（virtual memory）和物理内存（physical memory）之分了。<br />
　　我们又知道，Unix/Linux进程的虚拟地址空间被按用途被划分成了内核空间和用户空间。内核空间供操作系统的内核使用，用户空间供用户程序支配。其中用户空间又被划分为若干段，主要包括：代码段（.text），用来存放/映射用户程序的代码；数据段（.data），存放初始化的全局数据或静态数据，这部分在文件系统中也占据磁盘空间；.bss段（一直没找到一个亲切的翻译），存放为初始化的全局或静态数据，在程序加载时分配空间和初始化，这部分空间不占用磁盘空间（当然在可执行文件中要保留其大小）；堆栈段，用来保存程序执行时的上下文（局部变量、函数参数和返回地址等），在进程建立时由操作系统分配，空间较小且在运行时不可动态调整，增长方向因机器架构而异，IA上自高地址向下增长，堆栈不占用磁盘空间；堆，供用户在运行时动态地申请和使用，空间较大，未被申请的堆空间不可使用，也不会被映射到物理空间，堆随着用户程序申请向上增长，堆不占用磁盘空间。</p>
<p>　　这么长的开场白之后，我们还知道，new负责在运行时（通过运行时库）为用户程序在堆上申请空间。但，而且，当然，new出的只是虚拟空间。在未对该空间进行读写时，这些空间并未被映射到物理空间，即操作系统还没有为这段空间分配物理内存。只有当程序开始对刚刚申请的虚拟空间进行访问时，被操作系统的虚拟内存机制觉察到（页中断）这一请求，才会为访问地址所在的虚存页面分配和映射物理页面，访问才得以进行。可以使用下面程序对此作出验证，</p>

<div class="wp_codebox"><table><tr id="p256817"><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="p2568code17"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;stage 1...&quot;</span><span style="color: #000080;">&lt;&lt;</span>std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>p <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> <span style="color: #0000ff;">char</span><span style="color: #008000;">&#91;</span>1U<span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">30</span> <span style="color: #000040;">*</span> <span style="color: #0000dd;">2</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//~ 2GB</span>
&nbsp;
    sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;stage 2...&quot;</span><span style="color: #000080;">&lt;&lt;</span>std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">for</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">unsigned</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #008000;">&#40;</span>1U<span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">30</span><span style="color: #000040;">*</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #666666;">//~ access</span>
    <span style="color: #008000;">&#123;</span>
        p<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
        usleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1000</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//~ per millisecond</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　运行此程序，同时使用top命令观察。主要观察两项，new前后程序的虚存占用，以及stage 2中程序驻留内存（REsident Size，即物理内存）的变化。另外，为了观察方便，最好调整top命令，使其按内存占用对进程排序。</p>
<p>　　上面虽然没有介绍太多东西，但由于本人水平有限，难免会有错误及不清楚之处，如果“不幸”被你发现了，还请指出和补充之。<br />
　　关于内存管理，学习过程中总会发现“惊喜”，若要做到对内存知根知底，对内核和语言运行时库的研究是必要的。对于这些个“小惊喜”，一方面说明俺是个小菜，另一方面也预示着俺是个成长中的小菜。各位看官您见笑了;-)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2011/04/reserve-new-virtual-physical-memory/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>[STL]vector和deque的内存释放(clear)</title>
		<link>http://www.dutor.net/index.php/2011/04/vector-deque-clear-reserve/</link>
		<comments>http://www.dutor.net/index.php/2011/04/vector-deque-clear-reserve/#comments</comments>
		<pubDate>Sun, 10 Apr 2011 13:56:22 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[Cpp]]></category>
		<category><![CDATA[STL]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2551</guid>
		<description><![CDATA[　　关于C++ STL容器的默认内存管理，需参考allocator。
　　关于deque的内存模型及其clear操作，我不甚了了，请参考您使用的标准库的代码。
　　若想深入了解STL的实现，侯捷大叔的《STL源码剖析》是不错的入门资料，希望能够拜读。
　　C++标准中并未对STL的实现细节做过多规定，因此不同实现的细节和表现可能不同。

　　C++很复杂，但也并非无底黑洞。学好C++很难，但这种学习过程也会使你收获颇丰。
　　学习任何一种技术，都需要热情、激情和足够的耐心。
　　做好一件事，需要激情，同时激情常常来源于做好一件事情的满足感。
　　满足感会增强人分享的欲望，分享的欲望也常常会使人具有亲和力和感染力，使人觉得你有激情，反过来更有利于人做好一件事。
　　blabla, over~
]]></description>
			<content:encoded><![CDATA[<p>　　vector的clear成员函数可以清除vector中的元素，使其大小减至0。但它却不能减小vector占用的内存。</p>

<div class="wp_codebox"><table><tr id="p255118"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code" id="p2551code18"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008000;">&#40;</span>1U<span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">29</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;step into stage one...&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
    sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">30</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    v.<span style="color: #007788;">clear</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;step into stage two...&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
    sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">30</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　stage one定义了vector对象，含有2^29个int元素，占用2G内存。stage two调用vector对象的clear成员函数，清除其中所有对象。程序运行过程中，使用ps或者top或者其他工具查看内存占用，会发现，程序在stage one确实占用了大约2GB的内存，但在stage two，程序仍然占用着2G内存。事实上，vector的clear成员只负责对其中每一个元素调用其析构函数，将vector的size置零，并不负责释放vector本身占用的内存空间。</p>
<p>　　若想释放vector占用的空间，可以使用swap技巧，</p>

<div class="wp_codebox"><table><tr id="p255119"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code" id="p2551code19"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008000;">&#40;</span>1U<span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">29</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;step into stage one...&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
    sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">30</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">swap</span><span style="color: #008000;">&#40;</span>v<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;step into stage two...&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
    sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">30</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　vector<int>()使用vector的默认构造函数建立临时vector对象，再在该临时对象上调用swap成员，swap调用之后对象v占用的空间就等于一个默认构造的对象的大小（寥寥），临时对象就具有原来对象v的大小，而该临时对象随即就会被析构，从而其占用的空间也被释放。</p>
<p>　　并不是所有的STL容器的clear成员的行为都和vector一样。事实上，其他容器的clear成员都会释放其内存。比如另一个和vector类似的顺序容器deque，</p>

<div class="wp_codebox"><table><tr id="p255120"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code" id="p2551code20"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    deque<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> dq<span style="color: #008000;">&#40;</span>1U<span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">29</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;step into stage one...&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
    sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">30</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    dq.<span style="color: #007788;">clear</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;step into stage two...&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
    sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">30</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　观察上面程序的行为，会发现程序在stage two的内存占用也是寥寥的了。</p>
<p>　　另外，值得一提的是vector具有reserve成员，会提前为容器预留一定的空间，以防止后的push_back操作导致频繁地重新分配内存和移动元素。然而，据我观察，reserve并没有向系统申请内存。</p>
<p>　　关于C++ STL容器的默认内存管理，需参考allocator。<br />
　　关于deque的内存模型及其clear操作，我不甚了了，请参考您使用的标准库的代码。<br />
　　若想深入了解STL的实现，侯捷大叔的《STL源码剖析》是不错的入门资料，希望能够拜读。<br />
　　C++标准中并未对STL的实现细节做过多规定，因此不同实现的细节和表现可能不同。</p>
<p>　　C++很复杂，但也并非无底黑洞。学好C++很难，但这种学习过程也会使你收获颇丰。<br />
　　学习任何一种技术，都需要热情、激情和足够的耐心。<br />
　　做好一件事，需要激情，同时激情常常来源于做好一件事情的满足感。<br />
　　满足感会增强人分享的欲望，分享的欲望也常常会使人具有亲和力和感染力，使人觉得你有激情，反过来更有利于人做好一件事。<br />
　　blabla, over~</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2011/04/vector-deque-clear-reserve/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>关于头文件</title>
		<link>http://www.dutor.net/index.php/2011/04/about-header-files/</link>
		<comments>http://www.dutor.net/index.php/2011/04/about-header-files/#comments</comments>
		<pubDate>Sat, 09 Apr 2011 03:23:02 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[Cpp]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2547</guid>
		<description><![CDATA[　　头文件中通常包含有：函数原型（声明）、宏定义、内联函数定义。
　　头文件使用#include宏命令引入。有两种形式：#inlcude &#60;header.h>和#include "header.h". 两种形式的区别在于预处理器（preprocessor）查找头文件的方式的不同：对于前者，预处理器仅在系统预定义的标准路径中查找（标准查找路径由环境变量指明），比如/usr/include, /usr/local/include；对于后者，预处理器首先查找（源文件所在的）当前目录，若未找到，则到标准路径查找。另外，查找路径还可以通过编译器选项（-I for gcc）指定。通常，对于C/C++标准库和其他系统范围的程序库，使用&#60;>形式，对于程序本身定义的头文件，采用""形式。]]></description>
			<content:encoded><![CDATA[<p>　　头文件中通常包含有：函数原型（声明）、宏定义、内联函数定义。<br />
　　头文件使用#include宏命令引入。有两种形式：#inlcude &lt;header.h>和#include &#8220;header.h&#8221;. 两种形式的区别在于预处理器（preprocessor）查找头文件的方式的不同：对于前者，预处理器仅在系统预定义的标准路径中查找（标准查找路径由环境变量指明），比如/usr/include, /usr/local/include；对于后者，预处理器首先查找（源文件所在的）当前目录，若未找到，则到标准路径查找。另外，查找路径还可以通过编译器选项（-I for gcc）指定。通常，对于C/C++标准库和其他系统范围的程序库，使用&lt;>形式，对于程序本身定义的头文件，采用&#8221;"形式。<br />
　　编译器在传递参数给函数时，依据的是该函数的原型。因此，在调用外部函数时，务必包含其对应的头文件，否则，可能会出现传递的参数与函数实际使用的参数格式不一致的情况。瞧，</p>

<div class="wp_codebox"><table><tr id="p254721"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="code" id="p2547code21"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//~ foo.c</span>
<span style="color: #993333;">float</span> 
foo<span style="color: #009900;">&#40;</span><span style="color: #993333;">float</span> f<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> f <span style="color: #339933;">*</span> f<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #666666; font-style: italic;">//~ main.c</span>
<span style="color: #993333;">int</span>
main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">double</span> d <span style="color: #339933;">=</span> foo<span style="color: #009900;">&#40;</span><span style="color:#800080;">3.1415926</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>独立编译，</p>

<div class="wp_codebox"><table><tr id="p254722"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p2547code22"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">cc</span> foo.c main.c <span style="color: #660033;">-c</span>
$ <span style="color: #c20cb9; font-weight: bold;">cc</span> foo.o main.o <span style="color: #660033;">-omain</span>
$ .<span style="color: #000000; font-weight: bold;">/</span>main</pre></td></tr></table></div>

<p>　　你执行上面程序可能没发现什么问题，但在某些情况下，问题就来了。比如，如果编译器只使用栈来传递浮点数，main中向foo传递的是double（通常浮点字面常量被编译器解释为double），foo却按float处理参数，结果可想而知了。</p>
<p>　　对于内联函数（内联展开只是对编译器的建议），由于编译器在进行内联展开时需要看到函数的定义（而不仅仅是原<br />
型），所以，内联函数通常直接在头文件中声明和定义。如果把内联函数的定义同其他<br />
函数一样，将声明和定义分开（在单独的源文件中定义），那么该“内联”函数就只能在其所定义的文件中展开。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2011/04/about-header-files/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>何谓格式化输入/输出</title>
		<link>http://www.dutor.net/index.php/2010/10/format-stdio/</link>
		<comments>http://www.dutor.net/index.php/2010/10/format-stdio/#comments</comments>
		<pubDate>Fri, 22 Oct 2010 02:22:48 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2494</guid>
		<description><![CDATA[　　不多说，都在代码里了。
<pre lang="cpp" line="1">
#include <stdio.h>

int
main(int AC, char **AV)
{
    FILE *fd = fopen("data", "w+");
    fprintf(fd, "%x%c", 0x41, '1');
    fseek(fd, 0, SEEK_SET);
    int n;
    fscanf(fd, "%d", &#038;n);
    fseek(fd, 0, SEEK_SET);
    char s[4];
    int c = fread(s, 1, sizeof(s), fd);
    s[c] = '\0';
    printf("%d, %s\n", n, s);
    fclose(fd);
    return 0;
}
</pre>]]></description>
			<content:encoded><![CDATA[<p>　　不多说，都在代码里了。</p>

<div class="wp_codebox"><table><tr id="p249423"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="code" id="p2494code23"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;stdio.h&gt;</span>
&nbsp;
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> AC, <span style="color: #0000ff;">char</span> <span style="color: #000040;">**</span>AV<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">FILE</span> <span style="color: #000040;">*</span>fd <span style="color: #000080;">=</span> <span style="color: #0000dd;">fopen</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;data&quot;</span>, <span style="color: #FF0000;">&quot;w+&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">fprintf</span><span style="color: #008000;">&#40;</span>fd, <span style="color: #FF0000;">&quot;%x%c&quot;</span>, <span style="color: #208080;">0x41</span>, <span style="color: #FF0000;">'1'</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">fseek</span><span style="color: #008000;">&#40;</span>fd, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">SEEK_SET</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> n<span style="color: #008080;">;</span>
    <span style="color: #0000dd;">fscanf</span><span style="color: #008000;">&#40;</span>fd, <span style="color: #FF0000;">&quot;%d&quot;</span>, <span style="color: #000040;">&amp;</span>n<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">fseek</span><span style="color: #008000;">&#40;</span>fd, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">SEEK_SET</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">char</span> s<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">4</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> c <span style="color: #000080;">=</span> <span style="color: #0000dd;">fread</span><span style="color: #008000;">&#40;</span>s, <span style="color: #0000dd;">1</span>, <span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>s<span style="color: #008000;">&#41;</span>, fd<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    s<span style="color: #008000;">&#91;</span>c<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #FF0000;">'<span style="color: #006699; font-weight: bold;">\0</span>'</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;%d, %s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, n, s<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">fclose</span><span style="color: #008000;">&#40;</span>fd<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/10/format-stdio/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>几种排序算法</title>
		<link>http://www.dutor.net/index.php/2010/10/sorts-of-sort-methods/</link>
		<comments>http://www.dutor.net/index.php/2010/10/sorts-of-sort-methods/#comments</comments>
		<pubDate>Mon, 18 Oct 2010 01:28:11 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之算法神奇]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[排序]]></category>
		<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2484</guid>
		<description><![CDATA[　　简单实现了常见的几种内部排序算法，包括冒泡（Bubble），插入（Insert），快速排序（Quick Sort），堆排序（Heap Sort），归并（Merge），希尔排序（Shell Sort），并对这些算法的耗时在伪随机数上进行了简单的测试。
　　说明：
<ul>
	<li>没有实现计数、基数排序等线性复杂度的算法；</li>

	<li>各算法只是对算法思想的一次简单模拟，没有过多的优化；</li>

	<li>各排序主程序接口参数均为整型数组及元素个数；</li>

	<li>程序计时使用了glibc的gettimeofday()，因此。。。；</li>

	<li>归并排序中，每次调用都申请和释放堆空间，因此比较耗时。可以采用原地归并、使用全局/静态的方法加以优化；</li>

	<li>快速排序中，对待排子序列的长度进行的了判断，对短序列进行优先排序可以减小函数的递归深度（而不是次数）；</li>

	<li>希尔排序中，为了简洁，步长因子统一取做2.2（11/5）。</li>
</ul>]]></description>
			<content:encoded><![CDATA[<p>　　简单实现了常见的几种内部排序算法，包括冒泡（Bubble），插入（Insert），快速排序（Quick Sort），堆排序（Heap Sort），归并（Merge），希尔排序（Shell Sort），并对这些算法的耗时在伪随机数上进行了简单的测试。<br />
　　说明：</p>
<ul>
<li>没有实现计数、基数排序等线性复杂度的算法；</li>
<li>各算法只是对算法思想的一次简单模拟，没有过多的优化；</li>
<li>各排序主程序接口参数均为整型数组及元素个数；</li>
<li>程序计时使用了glibc的gettimeofday()，因此。。。；</li>
<li>归并排序中，每次调用都申请和释放堆空间，因此比较耗时。可以采用原地归并、使用全局/静态的方法加以优化；</li>
<li>快速排序中，对待排子序列的长度进行的了判断，对短序列进行优先排序可以减小函数的递归深度（而不是次数）；</li>
<li>希尔排序中，为了简洁，步长因子统一取做2.2（11/5）。</li>
</ul>
<p>　　下面是主程序，</p>

<div class="wp_codebox"><table><tr id="p248424"><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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
</pre></td><td class="code" id="p2484code24"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
<span style="color: #339933;">#include &lt;stdlib.h&gt;</span>
<span style="color: #339933;">#include &lt;unistd.h&gt;</span>
<span style="color: #339933;">#include &lt;memory.h&gt;</span>
<span style="color: #339933;">#include &lt;time.h&gt;</span>
<span style="color: #339933;">#include &lt;sys/time.h&gt; //~ gettimeofday()</span>
&nbsp;
<span style="color: #993333;">typedef</span> <span style="color: #993333;">void</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>SORTFUN<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> <span style="color: #339933;">*</span>a<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #339933;">#define ASIZE 24*1024 //~ array size</span>
<span style="color: #339933;">#define SCOUNT 6 //~ number of sort method</span>
<span style="color: #000000; font-weight: bold;">enum</span> <span style="color: #009900;">&#123;</span>BUBBLE<span style="color: #339933;">,</span> INSERT<span style="color: #339933;">,</span> QSORT<span style="color: #339933;">,</span> HEAP<span style="color: #339933;">,</span> MERGE<span style="color: #339933;">,</span> SHELL<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">char</span> <span style="color: #339933;">*</span>fname<span style="color: #009900;">&#91;</span>SCOUNT<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #ff0000;">&quot;Bubble&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Insert&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Qsort&quot;</span><span style="color: #339933;">,</span>
        <span style="color: #ff0000;">&quot;Heap&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Merge&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Shell&quot;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
SORTFUN fpointer<span style="color: #009900;">&#91;</span>SCOUNT<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//~ pointers to sort functions</span>
&nbsp;
<span style="color: #993333;">int</span> array<span style="color: #009900;">&#91;</span>SCOUNT<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>ASIZE<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//~ array(s) under sort.</span>
&nbsp;
<span style="color: #993333;">long</span> timeused<span style="color: #009900;">&#91;</span>SCOUNT<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//~ time taken by every sort function</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/*******************Generate random data*********************/</span>
<span style="color: #993333;">void</span>
gen_data<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    srand<span style="color: #009900;">&#40;</span>time<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//~ rand seeding</span>
    <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> ASIZE<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//~ generate random array[0]</span>
    <span style="color: #009900;">&#123;</span>
        array<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> rand<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">%</span> ASIZE<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> SCOUNT<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//~ copy array[0] to the rest</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> j <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> j <span style="color: #339933;">&lt;</span> ASIZE<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>j<span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            array<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> array<span style="color: #009900;">&#91;</span>i<span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #666666; font-style: italic;">//NOTE: using TWO loops to maximize caching</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/***********************Time the time**********************/</span>
<span style="color: #993333;">long</span>
timer<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//~ Current Time by millisecond</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">struct</span> timeval tv<span style="color: #339933;">;</span>
    gettimeofday<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>tv<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #009900;">&#40;</span>tv.<span style="color: #202020;">tv_sec</span> <span style="color: #339933;">*</span> <span style="color: #0000dd;">1000</span> <span style="color: #339933;">+</span> tv.<span style="color: #202020;">tv_usec</span> <span style="color: #339933;">/</span> <span style="color: #0000dd;">1000</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #993333;">int</span>
main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> AC<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>AV<span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//~ Both of AC and AV are fascinating ^_^</span>
<span style="color: #009900;">&#123;</span>
    gen_data<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">//NOTE: to disable a function, just comment it out below.</span>
    fpointer<span style="color: #009900;">&#91;</span>BUBBLE<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> bubble_sort<span style="color: #339933;">;</span>
    fpointer<span style="color: #009900;">&#91;</span>INSERT<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> insert_sort<span style="color: #339933;">;</span>
    fpointer<span style="color: #009900;">&#91;</span>QSORT<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> quick_sort<span style="color: #339933;">;</span>
    fpointer<span style="color: #009900;">&#91;</span>HEAP<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> heap_sort<span style="color: #339933;">;</span>
    fpointer<span style="color: #009900;">&#91;</span>MERGE<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> merge_sort<span style="color: #339933;">;</span>
    fpointer<span style="color: #009900;">&#91;</span>SHELL<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> shell_sort<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> SCOUNT<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #993333;">long</span> starttime <span style="color: #339933;">=</span> timer<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        SORTFUN fp <span style="color: #339933;">=</span> fpointer<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>fp<span style="color: #009900;">&#41;</span>
            fp<span style="color: #009900;">&#40;</span>array<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> ASIZE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        timeused<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> timer<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> starttime<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">//~ Header</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%%Method<span style="color: #000099; font-weight: bold;">\t</span><span style="color: #000099; font-weight: bold;">\t</span>%%Time<span style="color: #000099; font-weight: bold;">\t</span><span style="color: #000099; font-weight: bold;">\t</span>%%Elements<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: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;-----------------------------------------<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: #666666; font-style: italic;">//~ result</span>
    <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> SCOUNT<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%s<span style="color: #000099; font-weight: bold;">\t</span><span style="color: #000099; font-weight: bold;">\t</span>%ld<span style="color: #000099; font-weight: bold;">\t</span><span style="color: #000099; font-weight: bold;">\t</span>%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> fname<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> timeused<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> ASIZE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;<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: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>　　各种排序，</p>

<div class="wp_codebox"><table><tr id="p248425"><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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
</pre></td><td class="code" id="p2484code25"><pre class="c" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">/************************Bubble Sort**************************/</span>
<span style="color: #993333;">void</span>
bubble_sort<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> <span style="color: #339933;">*</span>a<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> n<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> n <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #339933;">--</span>i<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #993333;">int</span> issorted <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//~ flag, for some optimition</span>
        <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> j <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> j <span style="color: #339933;">&lt;</span> i<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>j<span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>a<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&gt;</span> a<span style="color: #009900;">&#91;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                issorted <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
                <span style="color: #993333;">int</span> tmp <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                a<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                a<span style="color: #009900;">&#91;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> tmp<span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>issorted<span style="color: #009900;">&#41;</span>
            <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/************************Insert Sort**************************/</span>
<span style="color: #993333;">void</span>
insert_sort<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> <span style="color: #339933;">*</span>a<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> n<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> n <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #993333;">int</span> j <span style="color: #339933;">=</span> i <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
        <span style="color: #993333;">int</span> tmp <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>j <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span> <span style="color: #339933;">&amp;&amp;</span> tmp <span style="color: #339933;">&lt;</span> a<span style="color: #009900;">&#91;</span>j<span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            a<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>j<span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
            <span style="color: #339933;">--</span>j<span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        a<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> tmp<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/************************Quick Sort**************************/</span>
<span style="color: #993333;">int</span>
partition<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> <span style="color: #339933;">*</span>a<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> n<span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//~ seperate a[], using a[0] as pivot</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> l <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> r <span style="color: #339933;">=</span> n<span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> pivot <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>l<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>l <span style="color: #339933;">&lt;</span> r<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span> l <span style="color: #339933;">&lt;</span> r <span style="color: #339933;">&amp;&amp;</span> a<span style="color: #009900;">&#91;</span><span style="color: #339933;">--</span>r<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&gt;</span> pivot<span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
        a<span style="color: #009900;">&#91;</span>l<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>r<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>l <span style="color: #339933;">&lt;</span> r <span style="color: #339933;">&amp;&amp;</span> a<span style="color: #009900;">&#91;</span><span style="color: #339933;">++</span>l<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&lt;</span> pivot<span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
        a<span style="color: #009900;">&#91;</span>r<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>l<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    a<span style="color: #009900;">&#91;</span>l<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> pivot<span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> l<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//~ return the final index of pivot</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #993333;">void</span>
quick_sort<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> <span style="color: #339933;">*</span>a<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> n<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>n <span style="color: #339933;">&lt;=</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>
        <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> m <span style="color: #339933;">=</span> partition<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>m <span style="color: #339933;">&lt;=</span> n <span style="color: #339933;">/</span> <span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        quick_sort<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> m<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        quick_sort<span style="color: #009900;">&#40;</span>a <span style="color: #339933;">+</span> m <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> n <span style="color: #339933;">-</span> m <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">else</span>
    <span style="color: #009900;">&#123;</span>
        quick_sort<span style="color: #009900;">&#40;</span>a <span style="color: #339933;">+</span> m <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> n <span style="color: #339933;">-</span> m <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        quick_sort<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> m<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/************************Quik Sort**************************/</span>
<span style="color: #993333;">void</span>
sift<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> <span style="color: #339933;">*</span>a<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> i<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> n<span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//~ sift to rebuild the heap rooted by a[i]</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> tmp <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #0000dd;">2</span><span style="color: #339933;">*</span>i <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span> <span style="color: #339933;">&lt;</span> n<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #993333;">int</span> j <span style="color: #339933;">=</span> <span style="color: #0000dd;">2</span><span style="color: #339933;">*</span>i <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>j <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span> <span style="color: #339933;">&lt;</span> n <span style="color: #339933;">&amp;&amp;</span> a<span style="color: #009900;">&#91;</span>j<span style="color: #339933;">+</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">&gt;</span> a<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
            <span style="color: #339933;">++</span>j<span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>a<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&gt;</span> tmp<span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            a<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
            i <span style="color: #339933;">=</span> j<span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">else</span>
            <span style="color: #000000; font-weight: bold;">break</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    a<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> tmp<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #993333;">void</span>
heap_sort<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> <span style="color: #339933;">*</span>a<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> n<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>n<span style="color: #339933;">-</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #0000dd;">2</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&gt;=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> <span style="color: #339933;">--</span>i<span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//~ build heap</span>
    <span style="color: #009900;">&#123;</span>
        sift<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> i<span style="color: #339933;">,</span> n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> n<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//~ rebuild the decreasing heap over and over</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #993333;">int</span> tmp <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        a<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>n<span style="color: #339933;">-</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        a<span style="color: #009900;">&#91;</span>n<span style="color: #339933;">-</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> tmp<span style="color: #339933;">;</span>
        sift<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> n <span style="color: #339933;">-</span> i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/***********************Merge Sort**********************/</span>
<span style="color: #993333;">void</span>
merge_sort<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> <span style="color: #339933;">*</span>a<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> n<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>n <span style="color: #339933;">==</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>
        <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> <span style="color: #339933;">*</span>ext <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>malloc<span style="color: #009900;">&#40;</span><span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> n <span style="color: #339933;">/</span> <span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    merge_sort<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> n <span style="color: #339933;">/</span> <span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    merge_sort<span style="color: #009900;">&#40;</span>a <span style="color: #339933;">+</span> n <span style="color: #339933;">/</span> <span style="color: #0000dd;">2</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span>n <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    memcpy<span style="color: #009900;">&#40;</span>ext<span style="color: #339933;">,</span> a<span style="color: #339933;">,</span> n <span style="color: #339933;">/</span> <span style="color: #0000dd;">2</span> <span style="color: #339933;">*</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> j <span style="color: #339933;">=</span> n <span style="color: #339933;">/</span> <span style="color: #0000dd;">2</span><span style="color: #339933;">,</span> k <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>i <span style="color: #339933;">&lt;</span> n <span style="color: #339933;">/</span> <span style="color: #0000dd;">2</span> <span style="color: #339933;">&amp;&amp;</span> j <span style="color: #339933;">&lt;</span> n<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>a<span style="color: #009900;">&#91;</span>j<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&lt;</span> ext<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
            a<span style="color: #009900;">&#91;</span>k<span style="color: #339933;">++</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>j<span style="color: #339933;">++</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">else</span>
            a<span style="color: #009900;">&#91;</span>k<span style="color: #339933;">++</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> ext<span style="color: #009900;">&#91;</span>i<span style="color: #339933;">++</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>i <span style="color: #339933;">&lt;</span> n <span style="color: #339933;">/</span> <span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span>
        a<span style="color: #009900;">&#91;</span>k<span style="color: #339933;">++</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> ext<span style="color: #009900;">&#91;</span>i<span style="color: #339933;">++</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>j <span style="color: #339933;">&lt;</span> n<span style="color: #009900;">&#41;</span>
        a<span style="color: #009900;">&#91;</span>k<span style="color: #339933;">++</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> a<span style="color: #009900;">&#91;</span>j<span style="color: #339933;">++</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    free<span style="color: #009900;">&#40;</span>ext<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">/***********************Shell Sort**********************/</span>
<span style="color: #993333;">void</span>
shell_sort<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> <span style="color: #339933;">*</span> a<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> n<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> step <span style="color: #339933;">=</span> n <span style="color: #339933;">/</span> <span style="color: #0000dd;">2</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>step <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> step<span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> n<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #993333;">int</span> tmp <span style="color: #339933;">=</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span>a <span style="color: #339933;">+</span> i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #993333;">int</span> j <span style="color: #339933;">=</span> i <span style="color: #339933;">-</span> step<span style="color: #339933;">;</span>
            <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>j <span style="color: #339933;">&gt;=</span> <span style="color: #0000dd;">0</span> <span style="color: #339933;">&amp;&amp;</span> tmp <span style="color: #339933;">&lt;</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span>a <span style="color: #339933;">+</span> j<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span>a <span style="color: #339933;">+</span> j <span style="color: #339933;">+</span> step<span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span>a <span style="color: #339933;">+</span> j<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                j <span style="color: #339933;">-=</span> step<span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
            <span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span>a <span style="color: #339933;">+</span> j <span style="color: #339933;">+</span> step<span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> tmp<span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>step <span style="color: #339933;">==</span> <span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span>
            step <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">else</span>
            step <span style="color: #339933;">=</span> step <span style="color: #339933;">*</span> <span style="color: #0000dd;">11</span> <span style="color: #339933;">/</span> <span style="color: #0000dd;">5</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//~ integer is better</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>　　对测试结果做一下简要的总结：</p>
<ul>
<li>快排不是盖的，在我有限的随机测试中，它始终是最快的；</li>
<li>这里的归并排序由于堆内存的频繁申请与释放，相比同量级的其它算法，是最慢的；</li>
<li>希尔排序相当给力，尽管步长因子选择很粗糙，但在我的测试中，还是超过了堆排序。这从侧面证明了，在接近有序时插入排序是很快的。事实上，插入排序，由于其简洁性，常常做为高级排序算法的末级算法（局部算法）。</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/10/sorts-of-sort-methods/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>没有malloc的单链表</title>
		<link>http://www.dutor.net/index.php/2010/10/linked-list-without-malloc/</link>
		<comments>http://www.dutor.net/index.php/2010/10/linked-list-without-malloc/#comments</comments>
		<pubDate>Tue, 05 Oct 2010 03:43:43 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2464</guid>
		<description><![CDATA[　　在StackOverflow上面看到的，分析一下下面的代码，对初学者理解什么是堆，什么是栈，对象是如何拷贝的有所帮助。
<pre lang="c" line="1">
#include <stdio.h>
typedef struct node
{
      int i;
      struct node *next;
}node;
node getnode(int a)
{
      struct node n;
      n.i=a;
      n.next=NULL;
      return n;
}
</pre>]]></description>
			<content:encoded><![CDATA[<p>　　在StackOverflow上面看到的，分析一下下面的代码，对初学者理解什么是堆，什么是栈，对象是如何拷贝的有所帮助。</p>

<div class="wp_codebox"><table><tr id="p246426"><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
34
35
36
37
38
39
40
</pre></td><td class="code" id="p2464code26"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
<span style="color: #993333;">typedef</span> <span style="color: #993333;">struct</span> node
<span style="color: #009900;">&#123;</span>
      <span style="color: #993333;">int</span> i<span style="color: #339933;">;</span>
      <span style="color: #993333;">struct</span> node <span style="color: #339933;">*</span>next<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>node<span style="color: #339933;">;</span>
node getnode<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> a<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
      <span style="color: #993333;">struct</span> node n<span style="color: #339933;">;</span>
      n.<span style="color: #202020;">i</span><span style="color: #339933;">=</span>a<span style="color: #339933;">;</span>
      n.<span style="color: #202020;">next</span><span style="color: #339933;">=</span>NULL<span style="color: #339933;">;</span>
      <span style="color: #b1b100;">return</span> n<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
     <span style="color: #993333;">int</span> i<span style="color: #339933;">;</span>
     node newtemp<span style="color: #339933;">,</span>root<span style="color: #339933;">,</span>temp<span style="color: #339933;">;</span>
     scanf<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d&quot;</span><span style="color: #339933;">,&amp;</span>i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
     root<span style="color: #339933;">=</span>getnode<span style="color: #009900;">&#40;</span>i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
     temp<span style="color: #339933;">=</span>root<span style="color: #339933;">;</span>
&nbsp;
     <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>i<span style="color: #339933;">--</span><span style="color: #009900;">&#41;</span>
     <span style="color: #009900;">&#123;</span>
         newtemp<span style="color: #339933;">=</span>getnode<span style="color: #009900;">&#40;</span>i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
         temp.<span style="color: #202020;">next</span><span style="color: #339933;">=&amp;</span>newtemp<span style="color: #339933;">;</span>
         <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>root.<span style="color: #202020;">next</span><span style="color: #339933;">==</span>NULL<span style="color: #009900;">&#41;</span>
         <span style="color: #009900;">&#123;</span>
            root<span style="color: #339933;">=</span>temp<span style="color: #339933;">;</span>
         <span style="color: #009900;">&#125;</span>
        temp<span style="color: #339933;">=*</span><span style="color: #009900;">&#40;</span>temp.<span style="color: #202020;">next</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
     <span style="color: #009900;">&#125;</span>
     temp<span style="color: #339933;">=</span>root<span style="color: #339933;">;</span>
&nbsp;
     <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span> temp.<span style="color: #202020;">next</span> <span style="color: #339933;">!=</span> NULL <span style="color: #009900;">&#41;</span>
     <span style="color: #009900;">&#123;</span>
         <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot; %d &quot;</span><span style="color: #339933;">,</span>temp.<span style="color: #202020;">i</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
         temp<span style="color: #339933;">=*</span><span style="color: #009900;">&#40;</span>temp.<span style="color: #202020;">next</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
     <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/10/linked-list-without-malloc/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>[转摘]代码优化概要</title>
		<link>http://www.dutor.net/index.php/2010/09/overlooked-essentials-for-optimizing-code/</link>
		<comments>http://www.dutor.net/index.php/2010/09/overlooked-essentials-for-optimizing-code/#comments</comments>
		<pubDate>Mon, 20 Sep 2010 03:54:21 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[边走编程]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[汇编]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2445</guid>
		<description><![CDATA[　　我编写程序至今有35年了，我做了很多关于程序执行速度方面优化的工(一个示例)，我也看过其它人做的优化。我发现有两个最基本的优化技术总是被人所忽略。
　　注意，这两个技术并不是避免时机不成熟的优化。并不是把冒泡排序变成快速排序（算法优化）。也不是语言或是编译器的优化。也不是把 i*4写成i<<2的优化。

　　这两个技术是：
<ul>
	<li>使用 一个profiler。</li>
	<li>查看程序执行时的汇编码。</li>
</ul>]]></description>
			<content:encoded><![CDATA[<p>　　本文由<a href="http://coolshell.cn/articles/2967.html" target="_blank">陈皓</a>译自Dr. Dobb’s Blogger的Walter Bright写的《<a href="http://www.drdobbs.com/blog/archives/2010/09/overlooked_esse.html" target="_blank">Overlooked Essentials For Optimizing Code</a>》.</p>
<hr />
　　我编写程序至今有35年了，我做了很多关于程序执行速度方面优化的工(一个示例)，我也看过其它人做的优化。我发现有两个最基本的优化技术总是被人所忽略。<br />
　　注意，这两个技术并不是避免时机不成熟的优化。并不是把冒泡排序变成快速排序（算法优化）。也不是语言或是编译器的优化。也不是把 i*4写成i<<2的优化。</p>
<p>　　这两个技术是：</p>
<ul>
<li>使用 一个profiler。</li>
<li>查看程序执行时的汇编码。</li>
</ul>
<p>　　使用这两个技术的人将会成功地写出运行快的代码，不会使用这两个技术的人则不行。下面让我为你细细道来。</p>
<h4>使用一个 Profiler</h4>
<p>　　我们知道，程序运行时的90%的时间是用在了10%的代码上。我发现这并不准确。一次又一次地，我发现，几乎所有的程序会在1%的代码上花了99%的运行时间。但是，是哪个1%？一个好的Profiler可以告诉你这个答案。就算我们需要使用100个小时在这1%的代码上进行优化，也比使用100个小时在其它99%的代码上优化产生的效益要高得多得多。</p>
<p>　　问题是什么？人们不用profiler？不是。我工作过的一个地方使用了一个华丽而奢侈的Profiler，但是购买这个Profiler后，它的包装3年还是那么的暂新。为什么人们不用？我真的不知道。有一次，我和我的同事去了一个负载过大的交易所，我同事坚持说他知道哪里是瓶颈，毕竟，他是一个很有经验的专家。最终，我把我的Profiler在他的项目上运行了一下，我们发现那个瓶颈完全在一个意想不到的地方。</p>
<p>　　就像是赛车一样。团队是赢在传感器和日志上，这些东西提供了所有的一切。你可以调整一下赛车手的裤子以让其在比赛过程中更舒服，但是这不会让你赢得比赛，也不会让你更有竞争力。如果你不知道你的速度上不去是因为引擎、排气装置、空体动力学、轮胎气压，或是赛车手，那么你将无法获胜。编程为什么会不同呢？只要没有测量，你就永远无法进步。</p>
<p>　　这个世界上有太多可以使用的Profiler了。随便找一个你就可以看到你的函数的调用层次，调用的次数，以前每条代码的时间分解表（甚至可以到汇编级）。我看过太多的程序员回避使用Profiler，而是把时间花在那些无用的，错误的方向上的“优化”，而被其竞争对手所羞辱。（译者陈皓注：使用Profiler时，重点需要关注：1）花时间多的函数以优化其算法，2）调用次数巨多的函数——如果一个函数每秒被调用300K次，你只需要优化出0.001毫秒，那也是相当大的优化。这就是作者所谓的1%的代码占用了99%的CPU时间）</p>
<h4>查看汇编代码</h4>
<p>几年前，我有一个同事，Mary Bailey，她在华盛顿大学教矫正代数（remedial algebra），有一次，她在黑板上写下：</p>
<p>x + 3 = 5</p>
<p>然后问他的学生“求解x”，然后学生们不知道答案。于是她写下：</p>
<p>__ + 3 = 5</p>
<p>　　然后，再问学生“填空”，所有的学生都可以回答了。未知数x就像是一个有魔法的字母让大家都在想“x意味着代数，而我没有学过代数，所以我就不知道这个怎么做”。</p>
<p>　　汇编程序就是编程世界的代数。如果某人问我“inline函数是否被编译器展开了？”或是问我“如果我写下i*4，编译器会把其优化为左移位操作吗？”。这个时候，我都会建议他们看看编译器的汇编码。这样的回答是不是很粗暴和无用？通常，在我这样回答了提问者后，提问都通常都会说，对不起，我不知道什么是汇编！甚至C++的专家都会这么回答。</p>
<p>　　汇编语言是最简单的编程语言了（就算是和C++相比也是这样的），如：</p>
<p>ADD ESI,x</p>
<p>就是（C风格的代码）</p>
<p>ESI += x;</p>
<p>而：</p>
<p>CALL foo</p>
<p>则是：</p>
<p>foo();</p>
<p>　　细节因为CPU的种类而不同，但这就是其如何工作的。有时候，我们甚至都不需要细节，只需要看看汇编码的长啥样，然后和源代码比一比，你就可以知道汇编代码很多很多了。</p>
<p>　　那么，这又如何帮助代码优化？举个例子，我几年前认识一个程序员认为他应该去发现一个新的更快的算法。他有一个benchmark来证明这个算法，并且其写了一篇非常漂亮的文章关于他的这个算法。但是，有人看了一下其原来算法以及新算法的汇编，发现了他的改进版本的算法允许其编译器把两个除法操作变成了一个。这和算法真的没有什么关系。我们知道除法操作是一个很昂贵的操作，并且其还在一个内嵌循环中，所以，他的改进版的算法当然要快一些。只需要在原来的算法上做一点点小的改动——使用一个除法操作，那么其原来的算法将会和新的一样快。而他的新发现什么也不是。</p>
<p>　　下一个例子，一个D用户张贴了一个 benchmark 来显示 dmd (Digital Mars D 编译器)在整型算法上的很糟糕，而ldc (LLVM D 编译器) 就好很多了。对于这样的结果，其相当的有意见。我迅速地看了一下汇编，发现两个编译器编译出来相当的一致，并没有什么明显的东西要对2：1这么大的不同而负责。但是我们看到有一个对long型整数的除法，这个除法调用了运行库。而这个库成为消耗时间的杀手，其它所有的加减法都没有速度上的影响。出乎意料地，benchmark 和算法代码生成一点关系也没有，完全就是long型整数的除法的问题。这暴露了在dmd的运行库中的long型除法的实现很差。修正后就可以提高速度。所以，这和编译器没有什么关系，但是如果不看汇编，你将无法发现这一切。</p>
<p>　　查看汇编代码经常会给你一些意想不到的东西让你知道为什么程序的性能是那样。一些意想不到的函数调用，预料不到的自傲，以及不应该存在的东西，等等其实所有的一切。但也不需要成为一个汇编代码的黑客才能干的事。</p>
<h4>结论</h4>
<p>　　如果你觉得需要程序有更好的执行速度，那么，最基本的方法就是使用一个profiler和愿意去查看一下其汇编代码以找到程序的瓶颈。只有找到了程序的瓶颈，此时才是真正在思考如何去改进的时候，比如思考一个更好的算法，使用更快的语言优化，等等。</p>
<p>　　常规的做法是制胜法宝是挑选一个最佳的算法而不是进行微优化。虽然这种做法是无可异议的，但是有两件事情是学校没有教给你而需要你重点注意的。第一个也是最重要的，如果你优化的算法没没有参与到你程序性能中的算法，那么你优化他只是在浪费时间和精力，并且还转移了你的注意力让你错过了应该要去优化的部分。第二点，算法的性能总和处理的数据密切相关的，就算是冒泡排序有那么多的笑柄，但是如果其处理的数据基本是排好序的，只有其中几个数据是未排序的，那么冒泡排序也是所有排序算法里性能最好的。所以，担心没有使用好的算法而不去测量，只会浪费时间，无论是你的还是计算机的。</p>
<p>　　就好像赛车零件的订购速底是不会让你更靠进冠军（就算是你正确安装零件也不会），没有Profiler，你不会知道问题在哪里，不去看汇编，你可能知道问题所在，但你往往不知道为什么。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/09/overlooked-essentials-for-optimizing-code/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>extern &#8220;C&#8221;</title>
		<link>http://www.dutor.net/index.php/2010/09/extern-c/</link>
		<comments>http://www.dutor.net/index.php/2010/09/extern-c/#comments</comments>
		<pubDate>Mon, 20 Sep 2010 03:17:23 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[Cpp]]></category>
		<category><![CDATA[mangling]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2443</guid>
		<description><![CDATA[　　在很多C/C++头文件中，你可能会经常看到使用extern "C"{}包含起来的代码。这种语法的存在是为了使C和C++代码能够兼容。兼容？C++对C本来不就是兼容的吗？确实，在语法层面，C++支持几乎所有C语法。但这里的兼容是目标文件或者库级别的兼容，包括两种情况下的兼容。一种是，在C++代码中调用已经存在的C代码写成的库；另一种是，使用C编写代码，而希望这些代码能够使C++可以调用。
　　若想继续讨论extern "C"，就不得不提name mangling。
　　我们知道，相比C，C++支持函数重载，支持命名空间，支持类以及成员函数。函数重载允许我们声明名字相同参数不同的函数，命名空间（namespace）和类为名字（或者说符号）划分了不同的域使得我们可以在不同域中使用完全相同的名字。而为了实现这种特性，C++就使用了name mangling。即是说，C++编译器在编译C++文件时，把每一个函数名“打乱”成与函数所在域、参数类型、调用约定相关的另外一个名字（因为汇编级别的代码中，所有符号都在同一个域）。由于C中并不存在这些特性，所以通常C编译器并不对符号进行mangling。]]></description>
			<content:encoded><![CDATA[<p>　　在很多C/C++头文件中，你可能会经常看到使用extern &#8220;C&#8221;{}包含起来的代码。这种语法的存在是为了使C和C++代码能够兼容。兼容？C++对C本来不就是兼容的吗？确实，在语法层面，C++支持几乎所有C语法。但这里的兼容是目标文件或者库级别的兼容，包括两种情况下的兼容。一种是，在C++代码中调用已经存在的C代码写成的库；另一种是，使用C编写代码，而希望这些代码能够使C++可以调用。<br />
　　若想继续讨论extern &#8220;C&#8221;，就不得不提name mangling。<br />
　　我们知道，相比C，C++支持函数重载，支持命名空间，支持类以及成员函数。函数重载允许我们声明名字相同参数不同的函数，命名空间（namespace）和类为名字（或者说符号）划分了不同的域使得我们可以在不同域中使用完全相同的名字。而为了实现这种特性，C++就使用了name mangling。即是说，C++编译器在编译C++文件时，把每一个函数名“打乱”成与函数所在域、参数类型、调用约定相关的另外一个名字（因为汇编级别的代码中，所有符号都在同一个域）。由于C中并不存在这些特性，所以通常C编译器并不对符号进行mangling。<br />
　　由于C++中这种mangling的存在，使C和C++在符号上不统一，无法直接相互调用。比如C中有这样一个函数，</p>

<div class="wp_codebox"><table><tr id="p244327"><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code" id="p2443code27"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//~ add.h</span>
<span style="color: #993333;">int</span> add<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span><span style="color: #339933;">,</span> <span style="color: #993333;">int</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">//~ add.c</span>
<span style="color: #993333;">int</span> add<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> a<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> b<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> a <span style="color: #339933;">+</span> b<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>使用gcc编译add.c。然后在C++代码中直接调用add函数，</p>

<div class="wp_codebox"><table><tr id="p244328"><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code" id="p2443code28"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//~ main.cpp</span>
<span style="color: #339933;">#include &lt;add.h&gt;</span>
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> a <span style="color: #339933;">=</span> add<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>这样编译main.cpp，</p>

<div class="wp_codebox"><table><tr id="p244329"><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code" id="p2443code29"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">gcc</span> <span style="color: #660033;">-c</span> add.c
$ <span style="color: #c20cb9; font-weight: bold;">g++</span> <span style="color: #660033;">-c</span> main.cpp
$ <span style="color: #c20cb9; font-weight: bold;">g++</span> main.o add.o <span style="color: #660033;">-o</span> main
main.o: In <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #000000; font-weight: bold;">`</span>main<span style="color: #ff0000;">':
main.cpp:(.text+0x13): undefined reference to `add(int, int)'</span>
collect2: <span style="color: #c20cb9; font-weight: bold;">ld</span> returned <span style="color: #000000;">1</span> <span style="color: #7a0874; font-weight: bold;">exit</span> status</pre></td></tr></table></div>

<p>错误提示add(int, int)为找到。将main.cpp编译成汇编后，查看调用add的代码为</p>

<div class="wp_codebox"><table><tr id="p244330"><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code" id="p2443code30"><pre class="asm" style="font-family:monospace;">    movl    $<span style="color: #0000ff;">1</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">esi</span> # 参数入栈
    movl    $<span style="color: #0000ff;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">edi</span> # 参数入栈
    <span style="color: #00007f; font-weight: bold;">call</span>    _Z3addii # 调用<span style="color: #00007f; font-weight: bold;">add</span><span style="color: #339933;">,</span> 注意符号
    movl    <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000ff;">4</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span>rbp<span style="color: #009900; font-weight: bold;">&#41;</span> # 返回值赋给<span style="color: #00007f; font-weight: bold;">int</span> a</pre></td></tr></table></div>

<p>　　解决这种情况的方法就是使用extern &#8220;C&#8221;，在add.h中，把add的声明放入extern &#8220;C&#8221;{}中。这样，g++就不会对add进行mangling，链接器就会在add.o中找到add并链接到main.o。通常，C代码的头文件（包括libc的头文件，比如string.h）中，函数的声明通常是这样的，</p>

<div class="wp_codebox"><table><tr id="p244331"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code" id="p2443code31"><pre class="c" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//~ add.h</span>
<span style="color: #339933;">#ifdef __cplusplus</span>
<span style="color: #000000; font-weight: bold;">extern</span> <span style="color: #ff0000;">&quot;C&quot;</span> <span style="color: #009900;">&#123;</span>
<span style="color: #339933;">#endif</span>
<span style="color: #993333;">int</span> add<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span><span style="color: #339933;">,</span> <span style="color: #993333;">int</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #339933;">#ifdef __cplusplus</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #339933;">#endif</span></pre></td></tr></table></div>

<p>这样一来，如果是C代码包含add.h，那么将是直接包含add函数的声明。如果是C++代码包含add.h，那么extern &#8220;C&#8221;就将会被引入。关于name mangling，请参考<a href="http://en.wikipedia.org/wiki/Name_mangling" target="_blank">这里</a>，还有<a href="http://www.kegel.com/mangle.html" target="_blank">这里</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/09/extern-c/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>副作用与顺序点</title>
		<link>http://www.dutor.net/index.php/2010/09/side-effect-and-sequence-point/</link>
		<comments>http://www.dutor.net/index.php/2010/09/side-effect-and-sequence-point/#comments</comments>
		<pubDate>Sat, 18 Sep 2010 16:17:47 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[副作用]]></category>
		<category><![CDATA[顺序点]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2437</guid>
		<description><![CDATA[　　那么，C/C++中，哪些地方是顺序点呢？
<ul>
	<li>每个表达式的结束处；</li>
	<li>函数调用中，在所有参数求值完成后，函数体开始执行前有一个顺序点，而参数间的逗号处则没有顺序点。所以f(++i, ++i)的行为也是未定义的；</li>
	<li>逻辑运算符&#038;&、&#124;&#124;还有条件运算符?:的第一个参数末尾处有一个顺序点；</li>
	<li>逗号表达式中每一个逗号处有一个顺序点。因此x = (++i, ++i)是有确定行为的；</li>
	<li>在每一个完整的变量声明处有一个顺序点，例如int i, j;中逗号和分号处分别有一个顺序点；</li>
	<li>for循环控制条件中的两个分号处各有一个顺序点。</li>
</ul>
　　那么，现在，这个程序有问题吗？
<pre lang="c" line="1">
int
main()
{
    int m = 1, n = 0;
    printf("%d, %d\n", m, n);
    m ^= n ^= m ^= n;
    printf("%d, %d\n", m, n);
    return 0;
}
</pre>]]></description>
			<content:encoded><![CDATA[<p>　　C/C++中有一个叫做<a href="http://en.wikipedia.org/wiki/Sequence_point" target="_blank">顺序点（Sequence Point）</a>的概念，通常我们并没有必要去了解和深究。但如果掌握了顺序点的概念，一些晦涩的表达式（比如某些无聊的面试题目）可能就会变得简单明了了。为了介绍顺序点，就不得不提到副作用（Side Effect）。<br />
　　所谓副作用，是相对于传统表达式而言的。例如，i = j * k没有副作用，而i = ++j * k++或者i = f(j) * g(k)就有副作用。即是说，如果变量在一个表达式的运算中改变了自己的值，则称这个表达式有副作用。而顺序点就是为限定这些副作用产生歧义或者不确定行为所设定的。程序或者表达式中，在任意一个顺序点，它之前的所有副作用都已经完成，它之后的所有副作用都尚未发生；任意两个顺序点之间的副作用的发生顺序都是未定义的。这样说可能并不太清楚，咱们来看一个例子，</p>

<div class="wp_codebox"><table><tr id="p243732"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code" id="p2437code32"><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>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> n <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> m <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">++</span>n<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">++</span>n<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">++</span>n<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">++</span>n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d, %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> m<span style="color: #339933;">,</span> n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>　　上面代码的输出应该是什么呢？答案是，it depends. 可能因你所使用的编译器的不同（甚至是版本的不同）而产生较大的差异。用标准的话说，这样的行为是未定义的（undefined）。可是，为什么呢？<br />
　　这是因为赋值表达式int m = (++n) + (++n) + (++n) + (++n);没有顺序点，或者说只在表达式结尾的分号处有一个顺序点。因此，各副作用的计算顺序是不确定的。即是说，在计算第一个++n时，不知道其他++n是否已经被计算过（计算了几个）。使用gcc 4.2.4，上面程序输出11, 4，使用vs2008，程序输出16, 4。<br />
　　<br />
　　那么，C/C++中，哪些地方是顺序点呢？</p>
<ul>
<li>每个表达式的结束处；</li>
<li>函数调用中，在所有参数求值完成后，函数体开始执行前有一个顺序点，而参数间的逗号处则没有顺序点。所以f(++i, ++i)的行为也是未定义的；</li>
<li>逻辑运算符&#038;&#038;、||还有条件运算符?:的第一个参数末尾处有一个顺序点；</li>
<li>逗号表达式中每一个逗号处有一个顺序点。因此x = (++i, ++i)是有确定行为的；</li>
<li>在每一个完整的变量声明处有一个顺序点，例如int i, j;中逗号和分号处分别有一个顺序点；</li>
<li>for循环控制条件中的两个分号处各有一个顺序点。</li>
</ul>
<p>　　如果你打算规规矩矩的写你的代码，这些都是可以通过使用括号和临时变量来避免未定义的行为的。总之，要保证，在两个相邻顺序点之间同一个变量不可以被修改两次以上或者同时有读取和修改，否则，就会产生未定义的行为。例如，i = ++i。<br />
　　那么，现在，这个程序有问题吗？</p>

<div class="wp_codebox"><table><tr id="p243733"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code" id="p2437code33"><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>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> m <span style="color: #339933;">=</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> n <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d, %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> m<span style="color: #339933;">,</span> n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    m <span style="color: #339933;">^=</span> n <span style="color: #339933;">^=</span> m <span style="color: #339933;">^=</span> n<span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d, %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> m<span style="color: #339933;">,</span> n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>除了顺序点，即把m ^= n ^= m ^= n;改做m^=n;n^=m;m^=n;上面程序还可能有其它问题。C++中，如果m和n如果是同一个整数的引用呢？C中，在操作类似数组之类的对象时，也有可能出现m,n指向同一对象的可能性，这时，这个对象就被清零了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/09/side-effect-and-sequence-point/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>守护进程的单例运行</title>
		<link>http://www.dutor.net/index.php/2010/09/daemon-process-singleton/</link>
		<comments>http://www.dutor.net/index.php/2010/09/daemon-process-singleton/#comments</comments>
		<pubDate>Tue, 14 Sep 2010 14:50:12 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[守护进程]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2432</guid>
		<description><![CDATA[　　由于<a href="http://www.dutor.net/index.php/2010/09/daemon-process/" target="_blank">守护进程</a>在后台运行，为系统或用户提供某种服务，因此通常只需要一个运行实例就可以了，而且在大部分情况下只能有一个实例在运行。例如cron进程，若有多个实例在运行，那么各个实例都会根据crontab执行一份用户指定的任务，岂不是乱了套了？还有其他很多守护进程是设备相关的，而这些设备有很可能是非共享的，所以这样的守护进程也不能运行多个。
　　文件锁和记录锁机制是一种实现守护进程单例运行的方法。如果每一个守护进程创建一个文件，并且在整个文件上加上一把锁，那就只允许创建一把这样的写锁，所以在此之后试图再创建一把这样的写锁就会失败，以此向后续守护进程的副本指明已经存在一个正在运行的副本了。守护进程终止时，这把锁将被自动删除。
<pre lang="c" line="1">
int
lockfile(int fd) //~ try to lock the file, affecting errno when it fails.
{
    struct flock fk;
    fk.l_type = F_WRLCK;
    fk.l_start = 0;
    fk.l_whence = SEEK_SET;
    fk.l_len = 0;
    return (fcntl(fd, F_SETLK, &#038;fk));
}
</pre>]]></description>
			<content:encoded><![CDATA[<p>　　由于<a href="http://www.dutor.net/index.php/2010/09/daemon-process/" target="_blank">守护进程</a>在后台运行，为系统或用户提供某种服务，因此通常只需要一个运行实例就可以了，而且在大部分情况下只能有一个实例在运行。例如cron进程，若有多个实例在运行，那么各个实例都会根据crontab执行一份用户指定的任务，岂不是乱了套了？还有其他很多守护进程是设备相关的，而这些设备有很可能是非共享的，所以这样的守护进程也不能运行多个。<br />
　　文件锁和记录锁机制是一种实现守护进程单例运行的方法。如果每一个守护进程创建一个文件，并且在整个文件上加上一把锁，那就只允许创建一把这样的写锁，所以在此之后试图再创建一把这样的写锁就会失败，以此向后续守护进程的副本指明已经存在一个正在运行的副本了。守护进程终止时，这把锁将被自动删除。</p>

<div class="wp_codebox"><table><tr id="p243234"><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
34
35
36
37
38
39
40
41
42
43
44
</pre></td><td class="code" id="p2432code34"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span>
lockfile<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> fd<span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//~ try to lock the file, affecting errno when it fails.</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">struct</span> flock fk<span style="color: #339933;">;</span>
    fk.<span style="color: #202020;">l_type</span> <span style="color: #339933;">=</span> F_WRLCK<span style="color: #339933;">;</span>
    fk.<span style="color: #202020;">l_start</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    fk.<span style="color: #202020;">l_whence</span> <span style="color: #339933;">=</span> SEEK_SET<span style="color: #339933;">;</span>
    fk.<span style="color: #202020;">l_len</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #009900;">&#40;</span>fcntl<span style="color: #009900;">&#40;</span>fd<span style="color: #339933;">,</span> F_SETLK<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>fk<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">int</span>
already_running<span style="color: #009900;">&#40;</span><span style="color: #993333;">const</span> <span style="color: #993333;">char</span><span style="color: #339933;">*</span> fname<span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">//~ return 1, if another daemon is running</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> fd<span style="color: #339933;">;</span>
    fd <span style="color: #339933;">=</span> open<span style="color: #009900;">&#40;</span>fname<span style="color: #339933;">,</span> O_RDWR<span style="color: #339933;">|</span>O_CREAT<span style="color: #339933;">,</span> S_IRUSR<span style="color: #339933;">|</span>S_IWUSR<span style="color: #339933;">|</span>S_IRGRP<span style="color: #339933;">|</span>S_IROTH<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> fd <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">//~ in daemon process, you should use syslog, instead of stdout, for logging</span>
        <span style="color: #666666; font-style: italic;">//~ syslog(LOG_ERR, &quot;cannot open %s: %s&quot;, fname, strerror(errno));</span>
        fprintf<span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;cannot open %s: %s&quot;</span><span style="color: #339933;">,</span> fname<span style="color: #339933;">,</span> strerror<span style="color: #009900;">&#40;</span>errno<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        fflush<span style="color: #009900;">&#40;</span>stdout<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        exit<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> lockfile<span style="color: #009900;">&#40;</span>fd<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> errno <span style="color: #339933;">==</span> EACCES <span style="color: #339933;">||</span> errno <span style="color: #339933;">==</span> EAGAIN <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">//~ syslog(LOG_ERR, &quot;cannot lock %s: %s&quot;, fname, strerror(errno));</span>
            fprintf<span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;cannot lock %s: %s&quot;</span><span style="color: #339933;">,</span> fname<span style="color: #339933;">,</span> strerror<span style="color: #009900;">&#40;</span>errno<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            close<span style="color: #009900;">&#40;</span>fd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #666666; font-style: italic;">//~ syslog(LOG_ERR, &quot;cannot lock %s: %s&quot;, fname, strerror(errno));</span>
        fprintf<span style="color: #009900;">&#40;</span>stdout<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;cannot lock %s: %s&quot;</span><span style="color: #339933;">,</span> fname<span style="color: #339933;">,</span> strerror<span style="color: #009900;">&#40;</span>errno<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        fflush<span style="color: #009900;">&#40;</span>stdout<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        exit<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    ftruncate<span style="color: #009900;">&#40;</span>fd<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">char</span> buf<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">16</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    sprintf<span style="color: #009900;">&#40;</span>buf<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%ld&quot;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">long</span><span style="color: #009900;">&#41;</span>getpid<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    write<span style="color: #009900;">&#40;</span>fd<span style="color: #339933;">,</span> buf<span style="color: #339933;">,</span> strlen<span style="color: #009900;">&#40;</span>buf<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/09/daemon-process-singleton/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>优先级 &amp;&amp; 求值顺序</title>
		<link>http://www.dutor.net/index.php/2010/09/precedence-evaluation-order/</link>
		<comments>http://www.dutor.net/index.php/2010/09/precedence-evaluation-order/#comments</comments>
		<pubDate>Tue, 14 Sep 2010 06:54:16 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[运算符]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2426</guid>
		<description><![CDATA[See this,
<pre lang="c" line="1">
int
main()
{
    int x = -1,
        y = -1,
        z = 0;
    printf("%d\n", ++x &#124;&#124; ++y &#038;& ++z);
    printf("%d, %d, %d\n", x, y, z);
    return 0;
}
</pre>
　　别说我无聊，没人（正常人）会写出这样的式子，但有些细节知道总比不知道的好。
　　&#038;&比&#124;&#124;优先级高。
　　但优先级和求值顺序是两码事。
　　&#124;&#124;和&#038;&的求值顺序都是从左到右。其它运算符只有三目运算和逗号运算符有特定顺序，而+ - * /等的操作数均无特定的求值顺序，即f(x) + g(x++)中那个函数首先被调用是未定义的。顺便提一句，函数的参数的求值顺序与其入栈顺序也是无关的，所以f(i++, i++, i++)的行为也是未知的。]]></description>
			<content:encoded><![CDATA[<p>See this,</p>

<div class="wp_codebox"><table><tr id="p242635"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code" id="p2426code35"><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>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> x <span style="color: #339933;">=</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span>
        y <span style="color: #339933;">=</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span>
        z <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><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: #339933;">++</span>x <span style="color: #339933;">||</span> <span style="color: #339933;">++</span>y <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">++</span>z<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d, %d, %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> x<span style="color: #339933;">,</span> y<span style="color: #339933;">,</span> z<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>and this,</p>

<div class="wp_codebox"><table><tr id="p242636"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code" id="p2426code36"><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>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> x <span style="color: #339933;">=</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span>
        y <span style="color: #339933;">=</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">,</span>
        z <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span>
        s <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><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: #339933;">++</span>x <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">++</span>y <span style="color: #339933;">||</span> <span style="color: #339933;">++</span>z <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">++</span>s<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d, %d, %d, %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> x<span style="color: #339933;">,</span> y<span style="color: #339933;">,</span> z<span style="color: #339933;">,</span> s<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>　　别说我无聊，没人（正常人）会写出这样的式子，但有些细节知道总比不知道的好。<br />
　　&#038;&#038;比||优先级高。<br />
　　但优先级和求值顺序是两码事。<br />
　　||和&#038;&#038;的求值顺序都是从左到右。其它运算符只有三目运算和逗号运算符有特定顺序，而+ &#8211; * /等的操作数均无特定的求值顺序，即f(x) + g(x++)中那个函数首先被调用是未定义的。顺便提一句，函数的参数的求值顺序与其入栈顺序也是无关的，所以f(i++, i++, i++)的行为也是未知的。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/09/precedence-evaluation-order/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Linux中实现30分钟无操作自动关机</title>
		<link>http://www.dutor.net/index.php/2010/09/linux-auto-halt/</link>
		<comments>http://www.dutor.net/index.php/2010/09/linux-auto-halt/#comments</comments>
		<pubDate>Wed, 08 Sep 2010 23:30:34 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[多线程]]></category>
		<category><![CDATA[守护进程]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2418</guid>
		<description><![CDATA[　　<a href="http://www.dutor.net/index.php/2010/09/daemon-process/" target="_blank">上一篇简要介绍了守护进程</a>，现在就来实践一下，写一个自动关机的小程序。该程序可以守护进程的方式运行，当用户在一定时间（比如30分钟）没有鼠标和键盘操作后就会自动关机。
　　这个程序利用了上篇文章中实现的daemonize函数，为程序创建了守护进程所需要的运行环境。
　　由于需要同时监听鼠标和键盘操作，所以需要采用多线程的方式来实现。其中两个线程分别监视鼠标和键盘，一旦检测到相应动作（鼠标点击和移动、击键等），全局时间戳stamp（time_t）就会被设成当前时间。主线程每隔一定时间（比如1秒）检查stamp，若当前时间值（time(NULL)）比stamp大30*60，则执行停机操作（使用system函数执行init 0命令，或者使用reboot函数）。
　　需要说明的是，共享变量stamp需要互斥地访问。另外，对鼠标事件的监听是借助于对设备文件/dev/input/mice的读取（阻塞方式），键盘的监听借助于对/dev/input/event3的阻塞读取，但我猜想在不同机器上可能会是其它诸如event0,event5之类的文件。
　　不足之处在于，无法对全屏模式进行判断，即是说，如果你全屏看一部较长的电影，可能会被关机……
　　如果你有好的方法来实现本文的功能，还请不吝赐教！]]></description>
			<content:encoded><![CDATA[<p>　　<a href="http://www.dutor.net/index.php/2010/09/daemon-process/" target="_blank">上一篇简要介绍了守护进程</a>，现在就来实践一下，写一个自动关机的小程序。该程序可以守护进程的方式运行，当用户在一定时间（比如30分钟）没有鼠标和键盘操作后就会自动关机。<br />
　　这个程序利用了上篇文章中实现的daemonize函数，为程序创建了守护进程所需要的运行环境。<br />
　　由于需要同时监听鼠标和键盘操作，所以需要采用多线程的方式来实现。其中两个线程分别监视鼠标和键盘，一旦检测到相应动作（鼠标点击和移动、击键等），全局时间戳stamp（time_t）就会被设成当前时间。主线程每隔一定时间（比如1秒）检查stamp，若当前时间值（time(NULL)）比stamp大30*60，则执行停机操作（使用system函数执行init 0命令，或者使用reboot函数）。</p>

<div class="wp_codebox"><table><tr id="p241837"><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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
</pre></td><td class="code" id="p2418code37"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
<span style="color: #339933;">#include &lt;stdlib.h&gt;</span>
<span style="color: #339933;">#include &lt;unistd.h&gt;</span>
<span style="color: #339933;">#include &lt;sys/types.h&gt;</span>
<span style="color: #339933;">#include &lt;fcntl.h&gt; //~ O_RDWR, S_IRWXU etc.</span>
<span style="color: #339933;">#include &lt;pthread.h&gt;</span>
<span style="color: #339933;">#include &lt;time.h&gt;</span>
<span style="color: #339933;">#include &lt;limits.h&gt;</span>
<span style="color: #339933;">#include &lt;signal.h&gt;</span>
&nbsp;
<span style="color: #993333;">void</span> daemonize<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//~ thread functions</span>
<span style="color: #993333;">void</span> <span style="color: #339933;">*</span>listen_ms<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">void</span> <span style="color: #339933;">*</span>listen_kb<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//~ time stamp, keeping the time</span>
<span style="color: #666666; font-style: italic;">//~ when the last KB or Mouse event happened.</span>
<span style="color: #993333;">volatile</span> time_t stamp<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//~ mutex keeping stamp consistent.</span>
pthread_mutex_t stamp_mutex<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">int</span>
main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    daemonize<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">//~ initialize the mutex, stamp</span>
    pthread_mutex_init<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>stamp_mutex<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">//time(&amp;stamp);</span>
    stamp <span style="color: #339933;">=</span> time<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">//~ create two threads monitoring the Mouse and Keyboard.</span>
    pthread_t ms_tid<span style="color: #339933;">,</span> kb_tid<span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>pthread_create<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>ms_tid<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> listen_ms<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        perror<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;pthread_create&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        exit<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>pthread_create<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>kb_tid<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> listen_kb<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        perror<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;pthread_create&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        exit<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> interval <span style="color: #339933;">=</span> <span style="color: #0000dd;">60</span> <span style="color: #339933;">*</span> <span style="color: #0000dd;">30</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        sleep<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        pthread_mutex_lock<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>stamp_mutex<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> time<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> stamp <span style="color: #339933;">&gt;</span> interval <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #808080; font-style: italic;">/*printf(&quot;shutdown\n&quot;);*/</span>
            <span style="color: #808080; font-style: italic;">/*fflush(stdin);*/</span>
            system<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;init 0&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        pthread_mutex_unlock<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>stamp_mutex<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #666666; font-style: italic;">//~ join the threads, though it'll never be excuted.</span>
    pthread_join<span style="color: #009900;">&#40;</span>ms_tid<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    pthread_join<span style="color: #009900;">&#40;</span>kb_tid<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">void</span> <span style="color: #339933;">*</span>
listen_ms<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span> <span style="color: #339933;">*</span> arg<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> fd <span style="color: #339933;">=</span> open<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;/dev/input/mice&quot;</span><span style="color: #339933;">,</span> O_RDONLY<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>fd <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        perror<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;open mice&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        exit<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #993333;">char</span> buf<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">256</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span> read<span style="color: #009900;">&#40;</span>fd<span style="color: #339933;">,</span> buf<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>buf<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #808080; font-style: italic;">/*printf(&quot;Moused Moved.\n&quot;);*/</span>
        pthread_mutex_lock<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>stamp_mutex<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">//time(&amp;stamp);</span>
        stamp <span style="color: #339933;">=</span> time<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        pthread_mutex_unlock<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>stamp_mutex<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    close<span style="color: #009900;">&#40;</span>fd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">void</span> <span style="color: #339933;">*</span>
listen_kb<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span> <span style="color: #339933;">*</span> arg<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> fd <span style="color: #339933;">=</span> open<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;/dev/input/event3&quot;</span><span style="color: #339933;">,</span> O_RDONLY<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>fd <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        perror<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;open event3&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        exit<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #993333;">char</span> buf<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">256</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span> read<span style="color: #009900;">&#40;</span>fd<span style="color: #339933;">,</span> buf<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>buf<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #808080; font-style: italic;">/*printf(&quot;Key Hit.\n&quot;);*/</span>
        pthread_mutex_lock<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>stamp_mutex<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">//time(&amp;stamp);</span>
        stamp <span style="color: #339933;">=</span> time<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        pthread_mutex_unlock<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>stamp_mutex<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    close<span style="color: #009900;">&#40;</span>fd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">void</span>
daemonize<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> fork<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
        exit<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    setsid<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    close<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    close<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    close<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> fd <span style="color: #339933;">=</span> open<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;/dev/null&quot;</span><span style="color: #339933;">,</span> O_RDWR<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">//int fd = open(&quot;log.txt&quot;, O_RDWR);</span>
    dup2<span style="color: #009900;">&#40;</span>fd<span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    dup2<span style="color: #009900;">&#40;</span>fd<span style="color: #339933;">,</span> <span style="color: #0000dd;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    chdir<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;/&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    umask<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    signal<span style="color: #009900;">&#40;</span>SIGCHLD<span style="color: #339933;">,</span> SIG_IGN<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>　　需要说明的是，共享变量stamp需要互斥地访问。另外，对鼠标事件的监听是借助于对设备文件/dev/input/mice的读取（阻塞方式），键盘的监听借助于对/dev/input/event3的阻塞读取，但我猜想在不同机器上可能会是其它诸如event0,event5之类的文件。<br />
　　不足之处在于，无法对全屏模式进行判断，即是说，如果你全屏看一部较长的电影，可能会被关机……<br />
　　如果你有好的方法来实现本文的功能，还请不吝赐教！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/09/linux-auto-halt/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>守护进程</title>
		<link>http://www.dutor.net/index.php/2010/09/daemon-process/</link>
		<comments>http://www.dutor.net/index.php/2010/09/daemon-process/#comments</comments>
		<pubDate>Wed, 08 Sep 2010 15:29:10 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[OS基础]]></category>
		<category><![CDATA[守护进程]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2415</guid>
		<description><![CDATA[　　守护进程（daemon process，又称精灵进程），是一种运行在后台，不需要与用户进行交互的程序，其特性与Windows中的<strong>服务</strong>类似。Linux/Unix系统中运行着很多这样的进程，且很多此类进程的进程名都采用name<strong><em>d</em></strong>的形式，比如httpd, vsftpd, inetd等。但这只是一种命名惯例，你完全可以采用其它的命名形式。
<h4>守护进程的特性</h4>
　　守护进程有种种特性，使之成为守护进程。
　　<strong>运行周期较长。</strong>守护进程通常在系统启动时由/etc/rc*.d中的启动脚本或者用户在终端手动启动，在系统结束时停止或由用户手动停止。不像普通进程那样在用户退出终端后就被停止，守护进程会一直运行（下面会看到守护进程在启动后会脱离执行它的终端）。
　　<strong>脱离其运行环境。</strong>守护进程没有控制终端。进程在创建时（fork）会继承父进程的PCB（进程控制块），因此会同时拥有父进程的许多资源和关系，比如打开的文件描述符、socket、环境变量、控制终端、进程组、登录会话等。而守护进程需要关闭这些资源、脱离这些关系。]]></description>
			<content:encoded><![CDATA[<p>　　守护进程（daemon process，又称精灵进程），是一种运行在后台，不需要与用户进行交互的程序，其特性与Windows中的<strong>服务</strong>类似。Linux/Unix系统中运行着很多这样的进程，且很多此类进程的进程名都采用name<strong><em>d</em></strong>的形式，比如httpd, vsftpd, inetd等。但这只是一种命名惯例，你完全可以采用其它的命名形式。</p>
<h4>守护进程的特性</h4>
<p>　　守护进程有种种特性，使之成为守护进程。<br />
　　<strong>运行周期较长。</strong>守护进程通常在系统启动时由/etc/rc*.d中的启动脚本或者用户在终端手动启动，在系统结束时停止或由用户手动停止。不像普通进程那样在用户退出终端后就被停止，守护进程会一直运行（下面会看到守护进程在启动后会脱离执行它的终端）。<br />
　　<strong>脱离其运行环境。</strong>守护进程没有控制终端。进程在创建时（fork）会继承父进程的PCB（进程控制块），因此会同时拥有父进程的许多资源和关系，比如打开的文件描述符、socket、环境变量、控制终端、进程组、登录会话等。而守护进程需要关闭这些资源、脱离这些关系。</p>
<h4>创建守护进程</h4>
<p>　　鉴于守护进程的这些特性，一个普通进程若想成为守护进程，就需要做一些特殊的操作。</p>
<h5>脱离控制终端</h5>
<p>　　多数用户进程都是从终端运行的，它由与终端关联的shell（用户登录时由login执行的，比如bash程序）经过fork/exec启动。用户程序启动后shell会等待该进程（wait或waitpid等）结束，如果该进程为后台运行，shell会立即返回命令提示符等待用户的其它操作，否则shell会在用户进程结束时才打印命令提示符。<br />
　　所以，为了能使守护进程运行后shell立即返回，通常在程序的入口采用下面的代码来完成：</p>

<div class="wp_codebox"><table><tr id="p241538"><td class="line_numbers"><pre>1
2
</pre></td><td class="code" id="p2415code38"><pre class="c" style="font-family:monospace;"><span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> fork<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
    exit<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>　　程序fork产生新进程，父进程立即返回（shell等待的就是父进程），shell进程的wait也会成功返回，而子进程则会继续执行。注意，此时子进程的父进程已经过继成为init进程（进程号为1）的子进程了。</p>
<h5>另立门户</h5>
<p>　　执行的上面的操作后，用户进程（子进程）并未真正脱离控制终端。因为子进程继承了父进程的关系，属于父进程所在的进程组，和父进程同属于一个作业，还隶属于控制终端所关联的登录会话（login session）。关于进程组、作业、登录会话等概念，请参考《高级Unix环境编程》(Advanced Programming of Unix Environment)，及Google。<br />
　　若想脱离这些复杂的关系，操作却十分简单，只须在子进程一开始，调用函数setsid()即可。setsid做了以下工作：脱离了原来的进程组和登录会话，创建新的进程组和会话，并担当其进程组的Group Leader和会话的Session Leader.<br />
　　这时候，该进程已经真正脱离了其控制终端，即是说，该进程在其原控制终端退出登录后仍可以在系统中运行。</p>
<h5>关闭继承打开的文件描述符</h5>
<p>　　控制终端，准确说是shell默认打开了三个文件，0代表标准输入，1代表标准输出，2代表标准错误输出。由该shell执行的进程也会继承打开这三个文件，所以它的所有子进程默认的输入和输出也都关联到此终端。因为守护进程也可能有其他用户进程通过exec系列函数执行，守护进程同样会继承这些文件描述符。因此在守护进程中需要关闭继承而来的所有描述符，APUE中stevens的代码：</p>

<div class="wp_codebox"><table><tr id="p241539"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code" id="p2415code39"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> close_all_fd<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
        <span style="color: #993333;">struct</span> rlimit lim<span style="color: #339933;">;</span>
        <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> i<span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>getrlimit<span style="color: #009900;">&#40;</span>RLIMIT_NOFILE<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>lim<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span>
                <span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>lim.<span style="color: #202020;">rlim_cur</span> <span style="color: #339933;">==</span> RLIM_INFINITY<span style="color: #009900;">&#41;</span>
                lim.<span style="color: #202020;">rlim_cur</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">1024</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> lim.<span style="color: #202020;">rlim_cur</span><span style="color: #339933;">;</span> i <span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<span style="color: #339933;">#ifdef MYPERF</span>
                <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">==</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>
                        <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
<span style="color: #339933;">#endif</span>
                <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>close<span style="color: #009900;">&#40;</span>i<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span> <span style="color: #339933;">&amp;&amp;</span> errno <span style="color: #339933;">!=</span> EBADF<span style="color: #009900;">&#41;</span>
                        <span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<h5>改变当前工作目录</h5>
<p>　　每个进程都有自己的当前工作目录，进程创建时默认继承父进程的工作目录。守护进程需要将当前工作目录改变，否则其所在目录所挂载的文件系统将无法卸载（可能是你不想要的），通常将其改变之根目录，方法是chdir(&#8220;/&#8221;);</p>
<h5>重设文件创建掩码</h5>
<p>　　为了能够自主控制文件创建权限位，常将文件创建掩码重设为0000，即umask(0);</p>
<h5>忽略SIGCHLD信号</h5>
<p>　　由于守护进程运行周期长，为了避免因为等待子进程而产生僵尸进程，通常需要忽略SIGCHLD信号：signal(SIGCHLD, SIG_IGN);</p>
<h4>总结</h4>
<p>　　方便起见，通常把创建守护进程的一系列操作包装为一个函数，在需要的地方调用即可：</p>

<div class="wp_codebox"><table><tr id="p241540"><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
</pre></td><td class="code" id="p2415code40"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">void</span> daemonize<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    daemonize<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #666666;">//~ other operations here.</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">void</span>
daemonize<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span> fork<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span>
        <span style="color: #0000dd;">exit</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    setsid<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    close<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//~ im so lazy a guy.</span>
    close<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    close<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #666666;">//~ you can use I/O functions, but to/from the black hole...</span>
    <span style="color: #0000ff;">int</span> fd <span style="color: #000080;">=</span> open<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;/dev/null&quot;</span>, O_RDWR<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    dup2<span style="color: #008000;">&#40;</span>fd, <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    dup2<span style="color: #008000;">&#40;</span>fd, <span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    chdir<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;/&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    umask<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">signal</span><span style="color: #008000;">&#40;</span>SIGCHLD, <span style="color: #0000ff;">SIG_IGN</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/09/daemon-process/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>共享变量的一个小问题</title>
		<link>http://www.dutor.net/index.php/2010/09/volatile-share-var/</link>
		<comments>http://www.dutor.net/index.php/2010/09/volatile-share-var/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 09:49:36 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[边走编程]]></category>
		<category><![CDATA[volatile]]></category>
		<category><![CDATA[多线程]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2412</guid>
		<description><![CDATA[　　正常情况下，在终端编译执行该多线程程序，首先打印n（0），5秒后再次打印n（1），然后该进程正常退出。
　　但，如果使用gcc编译此程序时，使用优化选项（比如-O1），再执行此程序。首先打印n（0），5秒后再次打印n（1），然后呢，然后就死循环啦！
　　为什么呢？看一看汇编代码就知道了，使用gcc -O1 -S命令编译第一段代码，得到的汇编码：
<pre lang="asm" line="1">
main:
    movl    n(%rip), %eax #从内存中取n值至寄存器eax
.L3:
    testl   %eax, %eax # 与测试eax
    je  .L3 # eax为0时跳转至标号L3处
    movl    $0, %eax
    ret
</pre>
　　真相大白了吧，那该怎么办？对，volatile，<a href="http://www.dutor.net/index.php/2010/08/volatile-const/" target="_blank">参看这里</a>。]]></description>
			<content:encoded><![CDATA[<p>　　看一个很简单的C程序：</p>

<div class="wp_codebox"><table><tr id="p241241"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code" id="p2412code41"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> n <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #993333;">int</span>
main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>n<span style="color: #009900;">&#41;</span>
        <span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>　　很明显，这是一个死循环，因为n的值总为0。再看：</p>

<div class="wp_codebox"><table><tr id="p241242"><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
</pre></td><td class="code" id="p2412code42"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> n <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #993333;">void</span> <span style="color: #339933;">*</span>foo<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">int</span>
main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    pthread_t pth_id<span style="color: #339933;">;</span>
    pthread_create<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>pth_id<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> foo<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>n<span style="color: #009900;">&#41;</span>
        <span style="color: #339933;">;</span>
    pthread_join<span style="color: #009900;">&#40;</span>pth_id<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">void</span> <span style="color: #339933;">*</span>foo<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span> arg<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;n: %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    sleep<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #339933;">++</span>n<span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;++n: %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> NULL<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>　　这是一个使用pthread库的多线程程序。主线程在以函数foo创建一个线程后，进入while循环。线程函数foo中，首先打印全局变量n的值，沉睡约5秒钟后，修改n，最后再次打印n值，然后该线程退出（等待主线程join）。<br />
　　正常情况下，在终端编译执行该多线程程序，首先打印n（0），5秒后再次打印n（1），然后该进程正常退出。<br />
　　但，如果使用gcc编译此程序时，使用优化选项（比如-O1），再执行此程序。首先打印n（0），5秒后再次打印n（1），然后呢，然后就死循环啦！<br />
　　为什么呢？看一看汇编代码就知道了，使用gcc -O1 -S命令编译第一段代码，得到的汇编码：</p>

<div class="wp_codebox"><table><tr id="p241243"><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code" id="p2412code43"><pre class="asm" style="font-family:monospace;">main<span style="color: #339933;">:</span>
    movl    n<span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span>rip<span style="color: #009900; font-weight: bold;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span> #从内存中取n值至寄存器<span style="color: #00007f;">eax</span>
<span style="color: #339933;">.</span>L3<span style="color: #339933;">:</span>
    testl   <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span> # 与测试<span style="color: #00007f;">eax</span>
    <span style="color: #00007f; font-weight: bold;">je</span>  <span style="color: #339933;">.</span>L3 # <span style="color: #00007f;">eax</span>为<span style="color: #0000ff;">0</span>时跳转至标号L3处
    movl    $<span style="color: #0000ff;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span>
    <span style="color: #00007f; font-weight: bold;">ret</span></pre></td></tr></table></div>

<p>　　真相大白了吧，那该怎么办？对，volatile，<a href="http://www.dutor.net/index.php/2010/08/volatile-const/" target="_blank">参看这里</a>。<br />
　　所以，在多线程程序中，共享变量除了同步问题外，还要注意编译器的优化和数据的一致性问题。除了多线程程序外，多进程通讯也会有相似的问题，另外，映射到内存的外部端口寄存器变量也需要使用volatile。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/09/volatile-share-var/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>const在C和C++中的区别</title>
		<link>http://www.dutor.net/index.php/2010/08/const-c-cpp-difference/</link>
		<comments>http://www.dutor.net/index.php/2010/08/const-c-cpp-difference/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 13:50:48 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[const]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2408</guid>
		<description><![CDATA[　　const在C，尤其是C++，是个老生常谈的问题，但这里不谈const具体有哪些特性，如何使用，而是说说const在C和C++中的区别。编译器，C使用gcc，C++使用g++，其它编译器（cl等）请自行验证。
　　在我的印象中，const就是<strong>常量</strong>（<em>const</em>ant）。但这并不是真的。在C中，const仅仅表示其所修饰对象<strong>不可修改</strong>。常量和所谓“不可修改”有什么区别呢？C中，const int N = 10; 这样的语句声明了一个<strong>整型数据</strong>，声明之后你不能再为其赋值，此即为<strong>不可修改</strong>。但在C中，N却不是常量，而诸如372, 3.72, 'A'之类才是常量，在C中定义常量通常使用#define。而在C++中，const int N = 10; 就会定义N为常量。
　　怎么证明呢？你可能知道，定义静态数组，必须使用整型常量指定其大小，那咱们就用这个特性来验证上面描述的观点。
<pre lang="c" line="1">
int
main(int argc, char **argv)
{
    const int N = 10;
    int a[N] = { 1, 2, 3 };
    return 0;
}
</pre>]]></description>
			<content:encoded><![CDATA[<p>　　const在C，尤其是C++，是个老生常谈的问题，但这里不谈const具体有哪些特性，如何使用，而是说说const在C和C++中的区别。编译器，C使用gcc，C++使用g++，其它编译器（cl等）请自行验证。<br />
　　在我的印象中，const就是<strong>常量</strong>（<em>const</em>ant）。但这并不是真的。在C中，const仅仅表示其所修饰对象<strong>不可修改</strong>。常量和所谓“不可修改”有什么区别呢？C中，const int N = 10; 这样的语句声明了一个<strong>整型数据</strong>，声明之后你不能再为其赋值，此即为<strong>不可修改</strong>。但在C中，N却不是常量，而诸如372, 3.72, &#8216;A&#8217;之类才是常量，在C中定义常量通常使用#define。而在C++中，const int N = 10; 就会定义N为常量。<br />
　　怎么证明呢？你可能知道，定义静态数组，必须使用整型常量指定其大小，那咱们就用这个特性来验证上面描述的观点。</p>

<div class="wp_codebox"><table><tr id="p240844"><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code" id="p2408code44"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span>
main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>argv<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">const</span> <span style="color: #993333;">int</span> N <span style="color: #339933;">=</span> <span style="color: #0000dd;">10</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> a<span style="color: #009900;">&#91;</span>N<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">2</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">3</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>　　使用g++编译这个程序，没有问题。但若使用gcc，你会得到如下错误信息</p>
<pre>
main.c: In function ‘main’:
main.c:19: error: variable-sized object may not be initialized
main.c:19: warning: excess elements in array initializer
</pre>
<p>　　<br />
　　但事情并未到此结束，如果你把上面代码中int a[N] = { 1, 2, 3 };的初始化列表去掉，即int a[N]; 然后就也能通过gcc的编译，更有甚者，如果你把const int N = 10;的const去掉：int N = 10; 也能通过gcc的编译！这是gcc所支持的特性，即<strong>动态数组</strong>。但最好不要这样做，因为gcc会为此生成大量代码。例如，这段代码</p>

<div class="wp_codebox"><table><tr id="p240845"><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code" id="p2408code45"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span>
main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>argv<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">const</span> <span style="color: #993333;">int</span> N <span style="color: #339933;">=</span> <span style="color: #0000dd;">10</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">int</span> a<span style="color: #009900;">&#91;</span>N<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>使用gcc生成的汇编代码：</p>

<div class="wp_codebox"><table><tr id="p240846"><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
34
35
</pre></td><td class="code" id="p2408code46"><pre class="asm" style="font-family:monospace;">&nbsp;
	<span style="color: #339933;">.</span>file	<span style="color: #7f007f;">&quot;main.c&quot;</span>
	<span style="color: #339933;">.</span>text
<span style="color: #339933;">.</span>globl main
	<span style="color: #339933;">.</span><span style="color: #000000; font-weight: bold;">type</span>	main<span style="color: #339933;">,</span> @function
main<span style="color: #339933;">:</span>
	leal	<span style="color: #0000ff;">4</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">ecx</span>
	andl	$<span style="color: #339933;">-</span><span style="color: #0000ff;">16</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">esp</span>
	pushl	<span style="color: #339933;">-</span><span style="color: #0000ff;">4</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">ecx</span><span style="color: #009900; font-weight: bold;">&#41;</span>
	pushl	<span style="color: #339933;">%</span><span style="color: #00007f;">ebp</span>
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">ebp</span>
	pushl	<span style="color: #339933;">%</span><span style="color: #00007f;">esi</span>
	pushl	<span style="color: #339933;">%</span><span style="color: #00007f;">ebx</span>
	pushl	<span style="color: #339933;">%</span><span style="color: #00007f;">ecx</span>
	subl	$<span style="color: #0000ff;">60</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">esp</span>
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">ecx</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span>
	movl	<span style="color: #0000ff;">4</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">eax</span><span style="color: #009900; font-weight: bold;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span>
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000ff;">44</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">ebp</span><span style="color: #009900; font-weight: bold;">&#41;</span>
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">gs</span><span style="color: #339933;">:</span><span style="color: #0000ff;">20</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span>
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000ff;">28</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">ebp</span><span style="color: #009900; font-weight: bold;">&#41;</span>
<span style="color: #009900; font-weight: bold;">&#91;</span> <span style="color: #339933;">...</span> <span style="color: #009900; font-weight: bold;">&#93;</span> # 此处略去n行
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">ecx</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">esp</span>
	movl	<span style="color: #339933;">-</span><span style="color: #0000ff;">28</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">ebp</span><span style="color: #009900; font-weight: bold;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">edx</span>
	xorl	<span style="color: #339933;">%</span><span style="color: #00007f;">gs</span><span style="color: #339933;">:</span><span style="color: #0000ff;">20</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">edx</span>
	<span style="color: #00007f; font-weight: bold;">je</span>	<span style="color: #339933;">.</span>L3
	<span style="color: #00007f; font-weight: bold;">call</span>	__stack_chk_fail
<span style="color: #339933;">.</span>L3<span style="color: #339933;">:</span>
	leal	<span style="color: #339933;">-</span><span style="color: #0000ff;">12</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">ebp</span><span style="color: #009900; font-weight: bold;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">esp</span>
	addl	$<span style="color: #0000ff;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">esp</span>
	popl	<span style="color: #339933;">%</span><span style="color: #00007f;">ecx</span>
	popl	<span style="color: #339933;">%</span><span style="color: #00007f;">ebx</span>
	popl	<span style="color: #339933;">%</span><span style="color: #00007f;">esi</span>
	popl	<span style="color: #339933;">%</span><span style="color: #00007f;">ebp</span>
	leal	<span style="color: #339933;">-</span><span style="color: #0000ff;">4</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">ecx</span><span style="color: #009900; font-weight: bold;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">esp</span>
	<span style="color: #00007f; font-weight: bold;">ret</span></pre></td></tr></table></div>

<p>　　整个汇编文件有96行之多。而使用g++（<strong>N为常量</strong>）编译生成的汇编文件只有23行：</p>

<div class="wp_codebox"><table><tr id="p240847"><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
</pre></td><td class="code" id="p2408code47"><pre class="asm" style="font-family:monospace;">	<span style="color: #339933;">.</span>file	<span style="color: #7f007f;">&quot;main.c&quot;</span>
	<span style="color: #339933;">.</span>text
<span style="color: #339933;">.</span>globl main
	<span style="color: #339933;">.</span><span style="color: #000000; font-weight: bold;">type</span>	main<span style="color: #339933;">,</span> @function
main<span style="color: #339933;">:</span>
<span style="color: #339933;">.</span>LFB0<span style="color: #339933;">:</span>
	<span style="color: #339933;">.</span>cfi_startproc
	<span style="color: #339933;">.</span>cfi_personality <span style="color: #0000ff;">0x0</span><span style="color: #339933;">,</span>__gxx_personality_v0
	pushl	<span style="color: #339933;">%</span><span style="color: #00007f;">ebp</span>
	<span style="color: #339933;">.</span>cfi_def_cfa_offset <span style="color: #0000ff;">8</span>
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">ebp</span>
	<span style="color: #339933;">.</span>cfi_offset <span style="color: #0000ff;">5</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000ff;">8</span>
	<span style="color: #339933;">.</span>cfi_def_cfa_register <span style="color: #0000ff;">5</span>
	subl	$<span style="color: #0000ff;">48</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">esp</span>
	movl	$<span style="color: #0000ff;">10</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000ff;">4</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">ebp</span><span style="color: #009900; font-weight: bold;">&#41;</span>
	movl	$<span style="color: #0000ff;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span>
	<span style="color: #00007f; font-weight: bold;">leave</span>
	<span style="color: #00007f; font-weight: bold;">ret</span>
	<span style="color: #339933;">.</span>cfi_endproc
<span style="color: #339933;">.</span>LFE0<span style="color: #339933;">:</span>
	<span style="color: #339933;">.</span><span style="color: #000000; font-weight: bold;">size</span>	main<span style="color: #339933;">,</span> <span style="color: #339933;">.-</span>main
	<span style="color: #339933;">.</span>ident	<span style="color: #7f007f;">&quot;GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3&quot;</span>
	<span style="color: #339933;">.</span>section	<span style="color: #339933;">.</span>note<span style="color: #339933;">.</span>GNU<span style="color: #339933;">-</span><span style="color: #000000; font-weight: bold;">stack</span><span style="color: #339933;">,</span><span style="color: #7f007f;">&quot;&quot;</span><span style="color: #339933;">,</span>@progbits</pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/08/const-c-cpp-difference/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>[C/C++]volatile</title>
		<link>http://www.dutor.net/index.php/2010/08/volatile-const/</link>
		<comments>http://www.dutor.net/index.php/2010/08/volatile-const/#comments</comments>
		<pubDate>Tue, 10 Aug 2010 12:05:25 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[const]]></category>
		<category><![CDATA[volatile]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2387</guid>
		<description><![CDATA[<h4>volatile</h4>
　　可能很多人都没用过<span class="word">C/C++</span>中的这个关键词，甚至不知道它的存在，本人以前也只是有所耳闻，但似懂非懂。
　　这是一个<strong>类型修饰符</strong>，位置同<span class="word">const</span>、<span class="word">static</span>等。一个使用<span class="word">volatile</span>修饰的变量，比如<em><span class="word">volatile int i;</span> </em>每次对该变量的直接引用，都会访问内存，而不是从寄存器中读取（如果其已经在寄存器中）。这样一来，<span class="word">volatile</span>似乎没什么用处，反倒会使数据的读取相对变慢很多。但是，如果没有<span class="word">volatile</span>，编译器可能会优化你的程序，使得数据从寄存器中读取，从而加快程序的运行，但如果这个变量是同其它进程/线程<strong>共享</strong>的，就可能造成数据的不一致。多线程情况下，你可以使用互斥机制来保证对共享数据访问的原子性。但是，在单片机等嵌入式环境中，硬件经常不会有这种<strong>互斥机制</strong>的支持，这时某些共享的数据（比如端口）就可能会产生不一致的情况。而使用<span class="word">volatile</span>就会使编译器不对代码进行优化，每次对该变量的访问都会从内存中读取。
　　下面通过观察使用<span class="word">volatile</span>前后编译产生的汇编代码的不同，来加深对<span class="word">volatile</span>关键词的理解。
<pre lang="asm" line="1">
[ ... ]
main:
[ ... ]
	call	foo # 调用函数foo，返回值保存至寄存器eax
	movl	%eax, 44(%esp) # 为i赋值
	movl	44(%esp), %edx # 读取i值
	movl	44(%esp), %ecx # 读取i值
	movl	44(%esp), %eax # 读取i值
	movl	%ecx, 16(%esp) # 参数k入栈，使用i值
	movl	%edx, 12(%esp) # 参数j入栈，使用i值
	movl	%eax, 8(%esp) # 参数i入栈
	movl	$.LC0, 4(%esp) # 格式字符串地址入栈
	call	__printf_chk
	movl	$0, %eax
	leave
	ret
[ ... ]
</pre>]]></description>
			<content:encoded><![CDATA[<h4>volatile</h4>
<p>　　可能很多人都没用过<span class="word">C/C++</span>中的这个关键词，甚至不知道它的存在，本人以前也只是有所耳闻，但似懂非懂。<br />
　　这是一个<strong>类型修饰符</strong>，位置同<span class="word">const</span>、<span class="word">static</span>等。一个使用<span class="word">volatile</span>修饰的变量，比如<em><span class="word">volatile int i;</span> </em>每次对该变量的直接引用，都会访问内存，而不是从寄存器中读取（如果其已经在寄存器中）。这样一来，<span class="word">volatile</span>似乎没什么用处，反倒会使数据的读取相对变慢很多。但是，如果没有<span class="word">volatile</span>，编译器可能会优化你的程序，使得数据从寄存器中读取，从而加快程序的运行，但如果这个变量是同其它进程/线程<strong>共享</strong>的，就可能造成数据的不一致。多线程情况下，你可以使用互斥机制来保证对共享数据访问的原子性。但是，在单片机等嵌入式环境中，硬件经常不会有这种<strong>互斥机制</strong>的支持，这时某些共享的数据（比如端口）就可能会产生不一致的情况。而使用<span class="word">volatile</span>就会使编译器不对代码进行优化，每次对该变量的访问都会从内存中读取。<br />
　　下面通过观察使用<span class="word">volatile</span>前后编译产生的汇编代码的不同，来加深对<span class="word">volatile</span>关键词的理解。<br />
　　对于下面的<span class="word">C</span>代码：</p>

<div class="wp_codebox"><table><tr id="p238748"><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="p2387code48"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;stdio.h&gt;</span>
&nbsp;
<span style="color: #0000ff;">int</span> foo<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">while</span><span style="color: #008000;">&#40;</span>i<span style="color: #000040;">++</span> <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">20</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> i<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> argc, <span style="color: #0000ff;">char</span> <span style="color: #000040;">**</span>argv<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> foo<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> j <span style="color: #000080;">=</span> i<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> k <span style="color: #000080;">=</span> i<span style="color: #008080;">;</span>
    <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;%d, %d, %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, i, j, k<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　代码中，使用<em>foo()</em>的返回值（20）来初始化整型变量<span class="word">i</span>。之所以不直接赋值，是为了<strong>防止</strong>编译器优化，下面对<span class="word">j,k</span>的赋值将直接使用<span class="word">20</span>，而不是<span class="word">i</span>，也不是寄存器。使用下面的命令编译：</p>

<div class="wp_codebox"><table><tr id="p238749"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p2387code49"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">gcc</span> <span style="color: #660033;">-S</span> <span style="color: #660033;">-O1</span> main.c <span style="color: #666666; font-style: italic;"># 优化等级1</span></pre></td></tr></table></div>

<p>　　产生的汇编代码：</p>

<div class="wp_codebox"><table><tr id="p238750"><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="p2387code50"><pre class="asm" style="font-family:monospace;"><span style="color: #009900; font-weight: bold;">&#91;</span> <span style="color: #339933;">...</span> <span style="color: #009900; font-weight: bold;">&#93;</span>
<span style="color: #339933;">.</span>LC0<span style="color: #339933;">:</span>
	<span style="color: #339933;">.</span>string	<span style="color: #7f007f;">&quot;%d, %d, %d\n&quot;</span>
<span style="color: #009900; font-weight: bold;">&#91;</span> <span style="color: #339933;">...</span> <span style="color: #009900; font-weight: bold;">&#93;</span>
main<span style="color: #339933;">:</span>
<span style="color: #009900; font-weight: bold;">&#91;</span> <span style="color: #339933;">...</span> <span style="color: #009900; font-weight: bold;">&#93;</span>
	<span style="color: #00007f; font-weight: bold;">call</span>	foo # 调用函数foo，返回值保存至寄存器<span style="color: #00007f;">eax</span>
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">16</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span> # 参数k入栈
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">12</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span> # 参数j入栈
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">8</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span> # 参数i入栈
	movl	$<span style="color: #339933;">.</span>LC0<span style="color: #339933;">,</span> <span style="color: #0000ff;">4</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span> # 格式字符串地址入栈
	movl	$<span style="color: #0000ff;">1</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span>
	<span style="color: #00007f; font-weight: bold;">call</span>	__printf_chk
	movl	$<span style="color: #0000ff;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span>
	<span style="color: #00007f; font-weight: bold;">leave</span>
	<span style="color: #00007f; font-weight: bold;">ret</span>
<span style="color: #009900; font-weight: bold;">&#91;</span> <span style="color: #339933;">...</span> <span style="color: #009900; font-weight: bold;">&#93;</span></pre></td></tr></table></div>

<p>　　可以看到，对<span class="word">j,k</span>的赋值都是由寄存器<span class="word">eax</span>进行的。下面把代码中的<em><span class="word">int i = foo();</span></em>换成<em><span class="word">volatile int i = foo();</span></em>，编译得到的汇编代码是：</p>

<div class="wp_codebox"><table><tr id="p238751"><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="p2387code51"><pre class="asm" style="font-family:monospace;"><span style="color: #009900; font-weight: bold;">&#91;</span> <span style="color: #339933;">...</span> <span style="color: #009900; font-weight: bold;">&#93;</span>
main<span style="color: #339933;">:</span>
<span style="color: #009900; font-weight: bold;">&#91;</span> <span style="color: #339933;">...</span> <span style="color: #009900; font-weight: bold;">&#93;</span>
	<span style="color: #00007f; font-weight: bold;">call</span>	foo # 调用函数foo，返回值保存至寄存器<span style="color: #00007f;">eax</span>
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">44</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span> # 为i赋值
	movl	<span style="color: #0000ff;">44</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">edx</span> # 读取i值
	movl	<span style="color: #0000ff;">44</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">ecx</span> # 读取i值
	movl	<span style="color: #0000ff;">44</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span> # 读取i值
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">ecx</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">16</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span> # 参数k入栈，使用i值
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">edx</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">12</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span> # 参数j入栈，使用i值
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">8</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span> # 参数i入栈
	movl	$<span style="color: #339933;">.</span>LC0<span style="color: #339933;">,</span> <span style="color: #0000ff;">4</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span> # 格式字符串地址入栈
	<span style="color: #00007f; font-weight: bold;">call</span>	__printf_chk
	movl	$<span style="color: #0000ff;">0</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">eax</span>
	<span style="color: #00007f; font-weight: bold;">leave</span>
	<span style="color: #00007f; font-weight: bold;">ret</span>
<span style="color: #009900; font-weight: bold;">&#91;</span> <span style="color: #339933;">...</span> <span style="color: #009900; font-weight: bold;">&#93;</span></pre></td></tr></table></div>

<p>　　可以看到，每次对i的访问都是从内存（栈）中读取的。</p>
<h4>volatile vs. const</h4>
<p>　　正像上面所描述的那样，<span class="word">volatile</span>的意思是<strong>“易变的”</strong>。<span class="word">C/C++</span>中还有另外一个关键词叫<span class="word">const</span>，用来限定变量不可被改变。似乎volatile和const意思相反，水火不容。但<span class="word"><em>volatile const int N = 0;</em></span>这样的语句是允许存在的。为什么呢？其实，这个语句可以这样来理解：变量<span class="word">N</span>在本程序（或者设备）中是不可（禁止）改变的，但它可能会被其它程序（或者设备）改变。你或许知道，<span class="word">const</span>只是编译器的限定，而没有执行期的检查，因此<span class="word">const</span>也只是限于单个进程，因此<span class="word">volatile</span>和<span class="word">const</span>这两个关键词并不冲突。<br />
　　另外，普通的整型<span class="word">const</span>变量，比如<em><span class="word">const int N = 10; int a[N];</span></em> 中，变量<span class="word">N</span>可能并不会被分配内存（除非程序里面有显式使用N地址的表达式）。但是，根据<span class="word">volatile</span>变量的特性，<em><span class="word">volatile const int N = 10;</span></em>中变量<span class="word">N</span>是一定会占用内存的。这一点，亦可以通过观察相应的汇编代码来验证。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/08/volatile-const/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>qsort</title>
		<link>http://www.dutor.net/index.php/2010/07/qsort/</link>
		<comments>http://www.dutor.net/index.php/2010/07/qsort/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 12:57:10 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[qsort]]></category>
		<category><![CDATA[排序]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2347</guid>
		<description><![CDATA[　　对qsort需要注意几点：
<ul>
	<li>qsort中第一个参数是待排序数组的开始地址，既然是数组，各元素就是同类型、同大小的对象，且数组是<strong>“一维数组”</strong>（即地址是连续的）；</li>
	<li>qsort用以区分对象的依据是第二和第三个参数，分别表示对象个数和每个对象的大小（字节）；</li>
	<li>qsort并不知道每个对象的类型和结构，排序准则由用户在第四个参数（比较函数）中指出，qsort按该比较函数准则的“升序”对数组进行排序；</li>
	<li>标准C不支持运算符重载，各对象的交换（因为这是qsort）靠的是逐字节的拷贝（memcpy?）。</li>
</ul>
　　在上面的两片代码中，待排序的对象一个是字符型指针，一个是char (*)[10]型数组。然后，就没有然后了。]]></description>
			<content:encoded><![CDATA[<p>　　Felix那里看到的，关于用qsort对指针式字符串数组和二维型字符串数组的排序的，觉得值得贴出来。注意下下面两片代码的区别。</p>

<div class="wp_codebox"><table><tr id="p234752"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code" id="p2347code52"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">const</span> <span style="color: #993333;">int</span> N <span style="color: #339933;">=</span> <span style="color: #0000dd;">4</span><span style="color: #339933;">;</span>
<span style="color: #993333;">char</span> <span style="color: #339933;">*</span>str<span style="color: #009900;">&#91;</span>N<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span> <span style="color: #ff0000;">&quot;xyz&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;cdef&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;abcd&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;caaa&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">int</span> cmp<span style="color: #009900;">&#40;</span><span style="color: #993333;">const</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>l<span style="color: #339933;">,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">void</span> <span style="color: #339933;">*</span>r<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>a <span style="color: #339933;">=</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span><span style="color: #339933;">**</span><span style="color: #009900;">&#41;</span>l<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>b <span style="color: #339933;">=</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span><span style="color: #339933;">**</span><span style="color: #009900;">&#41;</span>r<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> strcmp<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> b<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #993333;">int</span>
main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>argv<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    qsort<span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>str<span style="color: #339933;">,</span> N<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> cmp <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> N<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> str<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>


<div class="wp_codebox"><table><tr id="p234753"><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="p2347code53"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">const</span> <span style="color: #993333;">int</span> N <span style="color: #339933;">=</span> <span style="color: #0000dd;">4</span><span style="color: #339933;">;</span>
<span style="color: #993333;">char</span> str<span style="color: #009900;">&#91;</span>N<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">10</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span> <span style="color: #ff0000;">&quot;xyz&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;cdef&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;abcd&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;caaa&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">int</span>
main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>argv<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    qsort<span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>str<span style="color: #339933;">,</span> N<span style="color: #339933;">,</span>
            <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span><span style="color: #0000dd;">10</span><span style="color: #339933;">,</span>
            <span style="color: #009900;">&#40;</span> <span style="color: #993333;">int</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">const</span> <span style="color: #993333;">void</span><span style="color: #339933;">*,</span> <span style="color: #993333;">const</span> <span style="color: #993333;">void</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>strcmp <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> N<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> str<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>　　对qsort需要注意几点：</p>
<ul>
<li>qsort中第一个参数是待排序数组的开始地址，既然是数组，各元素就是同类型、同大小的对象，且数组是<strong>“一维数组”</strong>（即地址是连续的）；</li>
<li>qsort用以区分对象的依据是第二和第三个参数，分别表示对象个数和每个对象的大小（字节）；</li>
<li>qsort并不知道每个对象的类型和结构，排序准则由用户在第四个参数（比较函数）中指出，qsort按该比较函数准则的“升序”对数组进行排序；</li>
<li>标准C不支持运算符重载，各对象的交换（因为这是qsort）靠的是逐字节的拷贝（memcpy?）。</li>
</ul>
<p>　　在上面的两片代码中，待排序的对象一个是字符型指针，一个是char (*)[10]型数组。然后，就没有然后了。<br />
　　<br />
　　然后，上面代码，gcc编译出错，g++却可以。<br />
　　const int N = 4; char *str[N];可以。<br />
　　const int N = 4; char *str[N] = {&#8220;a&#8221;,&#8221;b&#8221;,&#8221;c&#8221;,&#8221;d&#8221;};却不可，何解？</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/07/qsort/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Unix/Linux环境下创建和使用静/动态库</title>
		<link>http://www.dutor.net/index.php/2010/07/dynamic-static-library/</link>
		<comments>http://www.dutor.net/index.php/2010/07/dynamic-static-library/#comments</comments>
		<pubDate>Sun, 04 Jul 2010 14:23:55 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[OS基础]]></category>
		<category><![CDATA[动态链接]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2340</guid>
		<description><![CDATA[<h4>动态链接库</h4>
　　动态库和静态库相似，也是各个目标文件的集合。但相比静态链接的程序，动态链接可执行程序要小得多：这类程序运行时需要外部共享 函数库的支持，因此好像并不完整。除了程序体小之外，动态链接允许程序包指定必须的库，而不必将库装入程序包内。动态链接技术还允许多个运行中的程序共享一个库，这样就不会出现同一代码的多份拷贝共占内存的情况了。由于这些原因，当前多数程序采用动态链接技术。
　　在Linux中的扩展名通常为.so。但在链接时，并不会被链接到可执行文件中，而是在执行时（需要时）由操作系统的动态加载模块动态地加载到内存，并链接到可执行文件地址空间的相应位置。
　　动态链接库的创建也分为编译和"归档"两个阶段，但不同的是在这两个阶段需要使用一些不同的命令选项。首先，需要将源文件编译成一种成为位置无关码（PIC: Position Independent Code）的目标文件，这种代码可以被加入到内存的任何位置却不需要加载器对其进行重定位，关于这种格式可以参考《链接器与加载器》和《程序员的自我修养--链接装载与库》中较为详尽的描述。接下来需要将这些位置无关码“归档”为.so文件。整个过程只需一个工具即可，即gcc。还是上面的源文件，执行以下命令：
<pre lang="bash" line="1">
$ cc -c -fpic plus.c sub.c
$ cc -shared -o libmath.so *.o
</pre>]]></description>
			<content:encoded><![CDATA[<h4>库的作用</h4>
<p>　　大体上库的存在，有两方面的原因，一是代码的复用，二是声明和实现的分离。将功能相近的使用模块封装成库，使代码的复用、管理和分发变得简单了许多，例如著名的开源图形库ncurses，你可以自行编译，更可以直接使用已经编译好的现成的库文件。另外，由于库是二进制文件，某种意义上讲，将功能的实现部分隐藏了起来，这就为商业代码的保护提供了一种方式。<br />
　　库文件按照链接方式和时机，可以分为动态库和静态库，下面分别介绍它们在Linux环境中的创建和使用方法。</p>
<h4>静态链接库</h4>
<p>　　静态库是指在程序的链接阶段，其中被用到的代码会被直接链接到可执行文件中的库。静态链接的可执行程序包含了其所需的全部库函数：所有库函数都连接到程序中。 这类程序是完整的，其运行不需要外部库的支持。 静态链接程序的优点之一是其安装之前不需要做环境准备工作 。<br />
　　Linux中，静态库的扩展名通常为.a，它仅仅是一些目标文件（.o）的归档（archive）或者说打包，另外，为了链接时能够快速地定位其中的符号（函数、变量名等），静态库还会包含一个对其中符号的索引。<br />
　　创建静态库的过程十分简单，除编译所必须的工具之外，要用到的命令只有两个ar和ranlib。ar可以将各个目标文件进行归档，ranlib对ar生成的归档文件（即静态库文件）进行索引。假设现在有这样几个源文件：plus.c, sub.c及相应的头文件，另外还有一个用来调用库文件中函数的主文件main.c，它们的内容分别是：<br />
plus.c,</p>

<div class="wp_codebox"><table><tr id="p234054"><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code" id="p2340code54"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &quot;plus.h&quot;</span>
<span style="color: #0000ff;">int</span>
plus<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> a, <span style="color: #0000ff;">int</span> b<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span> a <span style="color: #000040;">+</span> b<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>sub.c,</p>

<div class="wp_codebox"><table><tr id="p234055"><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code" id="p2340code55"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &quot;sub.h&quot;</span>
<span style="color: #0000ff;">int</span>
sub<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> a, <span style="color: #0000ff;">int</span> b<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span> a <span style="color: #000040;">-</span> b<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>main.c,</p>

<div class="wp_codebox"><table><tr id="p234056"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code" id="p2340code56"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;stdio.h&gt;</span>
<span style="color: #339900;">#include &lt;stdlib.h&gt;</span>
<span style="color: #339900;">#include &lt;unistd.h&gt;</span>
<span style="color: #339900;">#include &quot;plus.h&quot;</span>
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> argc, <span style="color: #0000ff;">char</span> <span style="color: #000040;">**</span>argv<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span> a <span style="color: #000080;">=</span> plus<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, <span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, a<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　下面将plus.c和sub.c编译，制作成静态库libmath.a，依次执行：</p>

<div class="wp_codebox"><table><tr id="p234057"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p2340code57"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">cc</span> <span style="color: #660033;">-c</span> plus.c sub.c
$ <span style="color: #c20cb9; font-weight: bold;">ar</span> rc libmath.a plus.o sub.o
$ ranlib libmath.a</pre></td></tr></table></div>

<p>　　现在我们的libmath.a静态库已经制作完成，其中使用了ar命令的两个选项，c表示若库文件不存在则创建之，r表示库文件中若已经存在某个目标文件，且较旧，则执行替换。使用这个静态库更加简单：</p>

<div class="wp_codebox"><table><tr id="p234058"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p2340code58"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">cc</span> main.c -L. <span style="color: #660033;">-lmath</span> <span style="color: #660033;">-o</span> main
$ .<span style="color: #000000; font-weight: bold;">/</span>main
<span style="color: #000000;">3</span></pre></td></tr></table></div>

<h4>动态链接库</h4>
<p>　　动态库和静态库相似，也是各个目标文件的集合。但相比静态链接的程序，动态链接可执行程序要小得多：这类程序运行时需要外部共享 函数库的支持，因此好像并不完整。除了程序体小之外，动态链接允许程序包指定必须的库，而不必将库装入程序包内。动态链接技术还允许多个运行中的程序共享一个库，这样就不会出现同一代码的多份拷贝共占内存的情况了。由于这些原因，当前多数程序采用动态链接技术。<br />
　　在Linux中的扩展名通常为.so。但在链接时，并不会被链接到可执行文件中，而是在执行时（需要时）由操作系统的动态加载模块动态地加载到内存，并链接到可执行文件地址空间的相应位置。<br />
　　动态链接库的创建也分为编译和&#8221;归档&#8221;两个阶段，但不同的是在这两个阶段需要使用一些不同的命令选项。首先，需要将源文件编译成一种成为位置无关码（PIC: Position Independent Code）的目标文件，这种代码可以被加入到内存的任何位置却不需要加载器对其进行重定位，关于这种格式可以参考《链接器与加载器》和《程序员的自我修养&#8211;链接装载与库》中较为详尽的描述。接下来需要将这些位置无关码“归档”为.so文件。整个过程只需一个工具即可，即gcc。还是上面的源文件，执行以下命令：</p>

<div class="wp_codebox"><table><tr id="p234059"><td class="line_numbers"><pre>1
2
</pre></td><td class="code" id="p2340code59"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">cc</span> <span style="color: #660033;">-c</span> <span style="color: #660033;">-fpic</span> plus.c sub.c
$ <span style="color: #c20cb9; font-weight: bold;">cc</span> <span style="color: #660033;">-shared</span> <span style="color: #660033;">-o</span> libmath.so <span style="color: #000000; font-weight: bold;">*</span>.o</pre></td></tr></table></div>

<p>　　这样，包含plus.o和sub.o的动态库文件libmath.so就创建完成了。其中cc（gcc的符号链接）命令的-fpic或-fPIC选项使之创建位置无关的目标文件，使用-shared选项可以创建最终的动态库文件。<br />
　　使用动态库文件有两种方法，一种是让操作系统的动态加载模块（如ld-linux.so.2）在执行时加载动态库。另一种是在代码中使用dl库动态加载库文件。<br />
　　先介绍下第一种方法。使用这种方法需要在编译可执行文件时指明库名及其路径（对于自己的编写的动态库而言）：</p>

<div class="wp_codebox"><table><tr id="p234060"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p2340code60"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">cc</span> main.c -L. <span style="color: #660033;">-lmath</span> <span style="color: #660033;">-o</span> main</pre></td></tr></table></div>

<p>　　这时可执行文件main就被创建了，上面的命令并没有将libmath.so中相应的目标代码链接到main中（你可以对比一下这里的main和静态链接的main的大小），只是在库中查找和确认main.c中用到的符号而已。但通常这个main现在还无法正常执行，这涉及到系统查找动态库的路径问题，系统通常只在某些指定的目录（标准路径）下查找所需的库文件，若在标准路径中无法找到所需的库，则会到环境变量LD_LIBRARY_PATH（如果存在的话）指定的目录下查找，若仍无法找到就会报错。因为libmath.so在main的当前目录中，而当前目录通常并不在标准路径之列。为了使libmath.so能够被找到和加载，你可以把它放到标准路径中，但更好的方法是将其所在目录加入到LD_LIBRARY_PATH变量中。执行下面的命令：</p>

<div class="wp_codebox"><table><tr id="p234061"><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code" id="p2340code61"><pre class="bash" style="font-family:monospace;">$ <span style="color: #007800;">LD_LIBRARY_PATH</span>=<span style="color: #007800;">$LD_LIBRARY_PATH</span>:. <span style="color: #666666; font-style: italic;"># 添加当前目录</span>
$ <span style="color: #7a0874; font-weight: bold;">export</span> LD_LIBRARY_PATH <span style="color: #666666; font-style: italic;"># 将环境变量导出，使其在子shell中可用</span>
$ .<span style="color: #000000; font-weight: bold;">/</span>main
<span style="color: #000000;">3</span></pre></td></tr></table></div>

<p>　　<br />
　　下面介绍使用dl库加载动态库，dl库中函数很少很简练，看main.c代码:</p>

<div class="wp_codebox"><table><tr id="p234062"><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
</pre></td><td class="code" id="p2340code62"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;stdio.h&gt;</span>
<span style="color: #339900;">#include &lt;stdlib.h&gt;</span>
<span style="color: #339900;">#include &lt;unistd.h&gt;</span>
<span style="color: #339900;">#include &lt;dlfcn.h&gt;</span>
<span style="color: #339900;">#include &quot;plus.h&quot;</span>
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> argc, <span style="color: #0000ff;">char</span> <span style="color: #000040;">**</span>argv<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span> lib_handle <span style="color: #000080;">=</span> dlopen<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;./libmath.so&quot;</span>, RTLD_LAZY<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>lib_handle<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">int</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>plus_ptr<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span>, <span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">=</span> dlsym<span style="color: #008000;">&#40;</span>lib_handle, <span style="color: #FF0000;">&quot;plus&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>plus_ptr<span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            <span style="color: #0000ff;">int</span> a <span style="color: #000080;">=</span> plus_ptr<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, <span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
            <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;%d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, a<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
        dlclose<span style="color: #008000;">&#40;</span>lib_handle<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　main.c中，首先使用dlopen打开需要的动态库，其中参数RTLD_LAZY指明仅当需要调用该库时才进行加载。dlopen返回一个句柄，dlsym使用该句柄和符号来取得相应函数的地址，这里使用int (*)(int, int)函数指针来接收plus函数的地址。接下来使用得到的函数指针调用相应的函数，最后通过dlclose函数来关闭句柄。编译这个程序需要使用dl动态链接库，因此需要使用gcc的-ldl选项：</p>

<div class="wp_codebox"><table><tr id="p234063"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p2340code63"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">cc</span> main.c <span style="color: #660033;">-ldl</span> <span style="color: #660033;">-o</span> main
$ .<span style="color: #000000; font-weight: bold;">/</span>main
<span style="color: #000000;">3</span></pre></td></tr></table></div>

<h4>.so与.a文件的对比</h4>
<p>　　最后附上libmath.a和libmath.so文件的内容，使用objdump的-d选项查看的：<br />
libmath.a,</p>
<pre>
In archive libmath.a:

plus.o:     file format elf32-i386
Disassembly of section .text:
00000000 &lt;plus>:
   0:	55                   	push   %ebp
   1:	89 e5                	mov    %esp,%ebp
   3:	8b 45 0c             	mov    0xc(%ebp),%eax
   6:	8b 55 08             	mov    0x8(%ebp),%edx
   9:	8d 04 02             	lea    (%edx,%eax,1),%eax
   c:	5d                   	pop    %ebp
   d:	c3                   	ret    

sub.o:     file format elf32-i386
Disassembly of section .text:
00000000 &lt;sub>:
   0:	55                   	push   %ebp
   1:	89 e5                	mov    %esp,%ebp
   3:	8b 45 0c             	mov    0xc(%ebp),%eax
   6:	8b 55 08             	mov    0x8(%ebp),%edx
   9:	89 d1                	mov    %edx,%ecx
   b:	29 c1                	sub    %eax,%ecx
   d:	89 c8                	mov    %ecx,%eax
   f:	5d                   	pop    %ebp
  10:	c3                   	ret
</pre>
<p>libmath.so:</p>
<pre>
libmath.so:     file format elf32-i386
Disassembly of section .init:
00000324 &lt;_init>:
 324:	55                   	push   %ebp
 325:	89 e5                	mov    %esp,%ebp
 327:	53                   	push   %ebx
 328:	83 ec 04             	sub    $0x4,%esp
......
0000044c &lt;plus>:
 44c:	55                   	push   %ebp
 44d:	89 e5                	mov    %esp,%ebp
 44f:	8b 45 0c             	mov    0xc(%ebp),%eax
 452:	8b 55 08             	mov    0x8(%ebp),%edx
 455:	8d 04 02             	lea    (%edx,%eax,1),%eax
 458:	5d                   	pop    %ebp
 459:	c3                   	ret
 45a:	90                   	nop
 45b:	90                   	nop

0000045c &lt;sub>:
 45c:	55                   	push   %ebp
 45d:	89 e5                	mov    %esp,%ebp
 45f:	8b 45 0c             	mov    0xc(%ebp),%eax
 462:	8b 55 08             	mov    0x8(%ebp),%edx
 465:	89 d1                	mov    %edx,%ecx
 467:	29 c1                	sub    %eax,%ecx
 469:	89 c8                	mov    %ecx,%eax
 46b:	5d                   	pop    %ebp
 46c:	c3                   	ret
 46d:	90                   	nop
 46e:	90                   	nop
 46f:	90                   	nop
......

Disassembly of section .fini:

000004a8 &lt;_fini>:
 4a8:	55                   	push   %ebp
 4a9:	89 e5                	mov    %esp,%ebp
 4ab:	53                   	push   %ebx
 4ac:	83 ec 04             	sub    $0x4,%esp
 4af:	e8 00 00 00 00       	call   4b4 &lt;_fini+0xc>
 4b4:	5b                   	pop    %ebx
 4b5:	81 c3 40 1b 00 00    	add    $0x1b40,%ebx
 4bb:	e8 d0 fe ff ff       	call   390 &lt;__do_global_dtors_aux>
 4c0:	59                   	pop    %ecx
 4c1:	5b                   	pop    %ebx
 4c2:	c9                   	leave
 4c3:	c3                   	ret
</pre>
<p>　　可见，相对.a，.so有很多额外的代码段，其中比较重要的是<_init>段和<_fini>段。它们分别进行一些前期和后期处理工作，例如<_init>通常在dlopen返回之前执行一些.so库中的一些初始化工作（C++中就可能是全局构造或者静态对象的构造函数）。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/07/dynamic-static-library/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>struct/class关键字何时是必须的？</title>
		<link>http://www.dutor.net/index.php/2010/05/is-struct-class-necessary/</link>
		<comments>http://www.dutor.net/index.php/2010/05/is-struct-class-necessary/#comments</comments>
		<pubDate>Fri, 21 May 2010 13:16:54 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[Cpp]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2288</guid>
		<description><![CDATA[　　在形如struct structName varName;的语句中，struct是必须的吗？这是一个显而易见的语法问题，但却容易被忽略，尤其容易被C+C++的同志们忽略。
　　在标准C中，struct关键字是必须的：
<pre lang="c" line="1">
struct structName {
    int n;
};
//~ typedef struct structName structName;
int
main()
{
    struct structName n;
    return 0;
}
</pre>
若没有前置的struct关键字，上面的代码就不能通过编译。我的gcc会提示"structName" undeclared, parse error before 'n'的错误。为了方便，通常会使用typedef struct structName structName;语句来为struct structName定义类型别名。
　　但是，在C++中，一般情况下，struct/class关键字就不是必须的。但是，在有些情况下struct/class关键字又是必须的，因为这时的名字structName有歧义性。这是因为，C/C++语言允许用户自定义类型和函数同名。]]></description>
			<content:encoded><![CDATA[<p>　　在形如struct structName varName;的语句中，struct是必须的吗？这是一个显而易见的语法问题，但却容易被忽略，尤其容易被C+C++的同志们忽略。<br />
　　在标准C中，struct关键字是必须的：</p>

<div class="wp_codebox"><table><tr id="p228864"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code" id="p2288code64"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">struct</span> structName <span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> n<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">//~ typedef struct structName structName;</span>
<span style="color: #993333;">int</span>
main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">struct</span> structName n<span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>若没有前置的struct关键字，上面的代码就不能通过编译。我的gcc会提示&#8221;structName&#8221; undeclared, parse error before &#8216;n&#8217;的错误。为了方便，通常会使用typedef struct structName structName;语句来为struct structName定义类型别名。<br />
　　但是，在C++中，一般情况下，struct/class关键字就不是必须的。但是，在有些情况下struct/class关键字又是必须的，因为这时的名字structName有歧义性。这是因为，C/C++语言允许用户自定义类型和函数同名。</p>

<div class="wp_codebox"><table><tr id="p228865"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code" id="p2288code65"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">struct</span> structName <span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> n<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">void</span> structName<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #993333;">int</span>
main<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    structName n<span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>上面代码，无论使用gcc还是g++，都不能通过编译，即使structName n;明显只能是一个变量定义语句。这时，就需要明确使用关键字struct，即struct structName n;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/05/is-struct-class-necessary/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[STL]容器适配器没有clear()</title>
		<link>http://www.dutor.net/index.php/2010/05/stl-adapter-none-clear/</link>
		<comments>http://www.dutor.net/index.php/2010/05/stl-adapter-none-clear/#comments</comments>
		<pubDate>Tue, 18 May 2010 01:44:01 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[边走编程]]></category>
		<category><![CDATA[STL]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2285</guid>
		<description><![CDATA[　　听XiaFei同学讲课，得知queque&#60;T>没有clear()成员函数，甚觉诧异，察知确凿。非但queue，其它容器适配器，如stack, priority_queque之流，亦无此clear，于此谨记。]]></description>
			<content:encoded><![CDATA[<p>　　听XiaFei同学讲课，得知queque&lt;T>没有clear()成员函数，甚觉诧异，察知确凿。非但queue，其它容器适配器，如stack, priority_queque之流，亦无此clear，于此谨记。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/05/stl-adapter-none-clear/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

