<?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>不敢流泪 &#187; C</title>
	<atom:link href="http://www.boluor.com/tag/c/feed" rel="self" type="application/rss+xml" />
	<link>http://www.boluor.com</link>
	<description></description>
	<lastBuildDate>Fri, 18 Jun 2010 05:38:01 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>小说const</title>
		<link>http://www.boluor.com/say-about-const.html</link>
		<comments>http://www.boluor.com/say-about-const.html#comments</comments>
		<pubDate>Fri, 04 Dec 2009 16:05:17 +0000</pubDate>
		<dc:creator>boluor</dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[C＋＋]]></category>

		<guid isPermaLink="false">http://www.boluor.com/?p=469</guid>
		<description><![CDATA[<p>	const用法比较复杂，小结下我常见的用法。</p>
<ol>
<li>限定类型修饰符。
<ol>
<li>int  const a = 1;	//int型常量。需要在定义时就初始化。</li>
<p> 　　
<li>int const arr[] = {1 ,2 , 3};	//数组中每一个元素都是常量。但是注意，不能把1中的a和arr[1]当作一样的。比如说可以紧接着这样定义：<br />
int testArr[a];	//正确<br />
int testArr[arr[1]];	//错误<br />
原因：const用于集合时，编译器不会把这个集合放到其符号表中，那么需要为其分配内存。但是虽然为其分配内存，其值却不能在编译阶段使用。</li>
</p><p> 　　
<li>int const *p;	//p是一个指向int型常量的指针。这里的p指针没必要在定义的时候就初始化。不过</li></p></ol></li></ol><p>&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>	const用法比较复杂，小结下我常见的用法。</p>
<ol>
<li>限定类型修饰符。
<ol>
<li>int  const a = 1;	//int型常量。需要在定义时就初始化。</li>
<p> 　　
<li>int const arr[] = {1 ,2 , 3};	//数组中每一个元素都是常量。但是注意，不能把1中的a和arr[1]当作一样的。比如说可以紧接着这样定义：<br />
int testArr[a];	//正确<br />
int testArr[arr[1]];	//错误<br />
原因：const用于集合时，编译器不会把这个集合放到其符号表中，那么需要为其分配内存。但是虽然为其分配内存，其值却不能在编译阶段使用。</li>
<p> 　　
<li>int const *p;	//p是一个指向int型常量的指针。这里的p指针没必要在定义的时候就初始化。不过*p是只读的，就是说不能通过*p来修改其所指向地址的值，但是可以通过其他指针修改。</li>
<p> 　　
<li>int  * const p;	// p是一个指针常量，指向int型变量。p本身不能改变。不过*p是可读可写的。</li>
<p> 　　
<li>自然，综合上面两个，就有了int const * const p; //意义不言自明了吧？</li>
<p> 　　
<li>class A; const A a; 简单的用法，跟上面是一样的。不过牵扯到类，就变得复杂了，有些我也搞不明白。</li>
</ol>
</li>
<li>转换规则<br />
　　描述起来费劲，不如看例子。<br />
　　const int *pa;<br />
　　int * pb;<br />
　　pb = pa;	//错误，不能直接将指向常量的指针转换为指向非常量的指针。<br />
　　pa = pb;	//正确。<br />
　　pb = (int *) pa;	//可以强制转换。不过转换后就失去了原有的保护机制。这时就可以通过pb修改pa所指向地址的值。
</li>
<p>　</p>
<li>作为函数参数
<ol>
 　　
<li>const修饰函数参数，就是希望函数不修改这个参数的值。对于值传递来说，没必要用const，因为函数即使修改了也是修改的副本，对实参没影响。但是这种拷贝毕竟费时耗内存，所以有了引用。此时又不希望引用被修改，所以可以加上const限定。比如：<br />
void fun( int const &#038; );</li>
<p> 　　
<li>但是记住，const仅仅只能希望程序不修改参数的值或者参数指向的地址的值，但不能杜绝它那么作。加入const可以让编译器在编译阶段就能检查出不希望的修改行为。但如果你强制修改或通过其他方式，照样是可以达到目的的。比如：<br />
void fun( int const *a){<br />
int *tmp = (int *)a;<br />
*tmp = *tmp +1;<br />
}
</li>
</ol>
</li>
<p>　</p>
<li>限定函数<br />
　　主要是限定类的成员函数。如果不希望一个成员函数修改任何一个类的成员数据，比如说这个函数只是打印信息。就可以像下面这样限定：<br />
class A{<br />
	void fun(&#8230;) const;	//不要把const写到最前面了，那意义可就变了。<br />
}<br />
　　但是，如果某个成员有mutable修饰，那上面的const就不对它保护了，程序可以随便修改。
</li>
<p>　</p>
<li>
修饰函数返回值<br />
　　如果像这样：const int fun( );使用，我觉得没有什么意义。因为，系统会将返回值复制到函数外部的临时存储单元中。如果是：const char * fun( ); 那么只能用const char *型变量来保存。const char * rtv = fun( ); </li>
<p>　</p>
<li>
多文件中共享const常量<br />
　　在C中定义时，如果是： int Max = 100 ; 默认的linkage就是extern，此时在其他文件中通过声明extern int Max ; 就可以使用Max 了。有时候需要在多个源文件中共享某个常量，此时注意了。在C++中，const定义默认具有 internal linkage，如果你定义int const Max = 100 ; 希望其他文件通过声明： extern int const Max ;来使用Max，那就会编译错误，提示找不到Max。此时需要显示的声明为Max为extern，即extern int const Max = 100 ;
</li>
<p>　</p>
<li>const其他<br />
　　const比#define要好得多的多。#define是在预处理时展开，定义的符号在编译完成之后，就不存在了，原来的地方全部成了立即数。const定义的常量在运行期间也是存在的，在编译阶段有可能加入符号表，方便查询，所以编译速度也不是大问题。由上也可推出，const会在某些场合比define少些内存分配。比如说：const str[] = “hello”; 如果程序中用到了多次str，那么str只需要一次内存分配，之后使用只要给出地址就行。而define：#define str “hello”; 将多次出现的地方全部替换成了立即数，那么每次使用时都需要为之分配内存，也就是说内存中会存在str的多个拷贝。
</li>
</ol>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>　　上面的代码可能有让你不舒服的地方，尤其 int const * p ; 而不是写作 const int *p ; 在说明我为什么这么写（下一篇文章）之前，问个问题，如果你能很清晰地回答正确，就没必要继续看了。<br />
　　参考：Dan Saks写的《const T vs T const》。<br />
　　［问题］<br />
		typedef void *VP;<br />
		const VP vectorTable[] = { … <data>&#8230;};<br />
		跟下面的是不是等价的？<br />
		const void *vectorTable[] = { &#8230;<data>&#8230; };</p>
]]></content:encoded>
			<wfw:commentRss>http://www.boluor.com/say-about-const.html/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>2009笔试+面试总结(一)</title>
		<link>http://www.boluor.com/2009-the-first-summary-of-writtens-and-interviews.html</link>
		<comments>http://www.boluor.com/2009-the-first-summary-of-writtens-and-interviews.html#comments</comments>
		<pubDate>Tue, 03 Nov 2009 15:31:32 +0000</pubDate>
		<dc:creator>boluor</dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[C＋＋]]></category>
		<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://www.boluor.com/?p=418</guid>
		<description><![CDATA[<p>　　十月份到现在参加了4个公司的笔试和面试，后天打算把三方协议签了，找工作就暂时尘埃落定了。开始专心复习之前，把笔试和面试中遇到的一些问题拿出来总结下。所列题目大致按照出题思想，非原题目。<br />
　　我面试的这4家IT公司，对于三点都非常重视。一个是基础知识，一个是运用知识，思考的能力，一个组织表达能力。按这三种分类记录下笔试和面试题目。</p>
<p><strong>［基础知识］</strong><br />
　　考察基础知识，在笔试题目最常见，占比例也最大。</p>
<ol>
<li>有n个节点的二叉树，其中有m个节点有两个孩子，问这棵树有多少颗叶子节点。
<blockquote><p>这题目其实是数据结构上的原题，不要被n迷惑了。</p></blockquote>
</li>
<p><span id="more-418"></span>
<li>问这段代码输出什么？考察C++基础。</li></p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:Courier new,verdana;"><span style="color: #0000ff;">class</span> A<span style="color: #008000;">&#123;</span> 
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span> 
<span style="color: #0000ff;">int</span> x<span style="color: #008000;">&#4</span></pre></div></div></ol><p>&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>　　十月份到现在参加了4个公司的笔试和面试，后天打算把三方协议签了，找工作就暂时尘埃落定了。开始专心复习之前，把笔试和面试中遇到的一些问题拿出来总结下。所列题目大致按照出题思想，非原题目。<br />
　　我面试的这4家IT公司，对于三点都非常重视。一个是基础知识，一个是运用知识，思考的能力，一个组织表达能力。按这三种分类记录下笔试和面试题目。</p>
<p><strong>［基础知识］</strong><br />
　　考察基础知识，在笔试题目最常见，占比例也最大。</p>
<ol>
<li>有n个节点的二叉树，其中有m个节点有两个孩子，问这棵树有多少颗叶子节点。</p>
<blockquote><p>这题目其实是数据结构上的原题，不要被n迷惑了。</p></blockquote>
</li>
<p><span id="more-418"></span>
<li>问这段代码输出什么？考察C++基础。</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:Courier new,verdana;"><span style="color: #0000ff;">class</span> A<span style="color: #008000;">&#123;</span> 
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span> 
<span style="color: #0000ff;">int</span> x<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span><span style="color: #0000ff;">return</span> <span style="color: #0000dd;">2</span><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;">class</span> B <span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> A<span style="color: #008000;">&#123;</span> 
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span> 
<span style="color: #0000ff;">int</span> x<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span><span style="color: #0000ff;">return</span> <span style="color: #0000dd;">3</span><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;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span> 
A <span style="color: #000040;">*</span>a <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> 
A <span style="color: #000040;">*</span>b <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> B<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> a<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>x<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&lt;&lt;</span> b<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>x<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&lt;&lt;</span>endl<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></div></div>

<p>　　<br />
<blockquote>类A中的函数x并非虚函数，所以不会发生动态绑定。</p></blockquote>
</li>
<li>
　　下列哪个表达式是错误的?<br />
　　int a = 10;<br />
　　1. (a++) += a;<br />
　　2. (++a) += (a++);<br />
　　<br />
<blockquote>a++其实是分三个步骤的：{tmp=a;++a;return tmp;}所以a++不能作为左值。</p></blockquote>
</li>
<li>
　　问下面的程序需要几次才能跳出循环?</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;">　　<span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> a <span style="color: #339933;">=</span><span style="color: #0000dd;">5</span><span style="color: #339933;">;</span>
　　<span style="color: #993333;">int</span> b <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> a<span style="color: #339933;">+</span>b <span style="color: #339933;">&gt;=</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
   　　　b<span style="color: #339933;">--;</span>
　　<span style="color: #009900;">&#125;</span></pre></div></div>

<p>　　<br />
<blockquote>C++中有符号和无符号类型之间的转换，要遵循一个原则：所定义的转换规则需要保护操作数的精度。比如long和unsigned int类型，只要机器上的long型足够表示unsigned int型的所有值，就将unsigned int转换为long型，否则，将两个操作数都转换为unsigned long。而对于包含signed 和 unsigned int型的表达式，其转换则是将signed型数值转换为unsigned型。如果此时将int转换为unsigned int，而int型数值恰好为负数，那这带来了副作用。此题就是一个例子。</p></blockquote>
</li>
<li>
　　union{<br />
　　int i;<br />
　　char x[2];<br />
　　}a;</p>
<p>　　a.x[0] = 8;<br />
　　a.x[1] = 1;<br />
　　问 a.i为多少?<br />
　　<br />
<blockquote>首先要了解的是，数据在内存中的存储方式。比如一个int型数，4个字节，表示为ABCD，在内存其实是DCBA保存的。那么看这题，内存中保存的是：00001000 00000001 00000000 00000000.根据上面的规则，那么用int来读取这段数据，即为00000000 00000000 00000001 00001000，即264.</p></blockquote>
</li>
<li>
　　map,set,hashmap和multimap,有个与其他三个数据结构不同的是哪一个?<br />
　　<br />
<blockquote>hashmap，采用和其他三种都不同的方式。</p></blockquote>
</li>
<li>
　　如果一个数列中的元素距离他们各自最终的位置都很近，那么哪一种算法最省时间？（直接插入，堆排序，快速排序，选择排序）<br />
　　<br />
<blockquote>我感觉是直接插入排序，当然还需要测试。</p></blockquote>
</li>
<li>
　　const char *和char * const 的区别。<br />
　　　<br />
<blockquote>const char *p;结合的方式是自右向左。所以p首先是个指针，然后个char型指针，然后他指向的是个const,此时，p本身的值可以改变的，但是不能通过p来修改p所指向区域A的值，但A可以通过其他指针修改。同理，char * const p，p首先是个const对象，之后才是指向char型的指针，此时p本身是不能修改的。</p></blockquote>
</li>
<li>
　　问下面的结果？<br />
　　char a = 50;<br />
　　int i = sizeof( a = (a+205));<br />
　　问 i 和 a各为多少?<br />
　　<br />
<blockquote>i为1大家都可以看出来，但a为多少相信就不是那么容易答对了。答-1的算好的，说255的就可以回去看计组了。sizeof(A)是个大难点，尤其是A如果是struct类型的时候。此题中，sizeof(A)的值其实是在编译阶段就已经确定了，所以根本没有运行a = a+205 这一步。在编译完成后，这句就相当于int i = 1;</p></blockquote>
</li>
<li>
　　计算机网络单播，组播，广播的区别。路由器和交换机的作用和原理。ARP协议的内容，以及其他相关的PPPOE协议的知识。
</li>
<li>
　　修改错误的代码：快排和堆排序。这完全的基本功了，为了面试，多练习在纸上写程序吧。
	</li>
</ol>
<p>　　类似的题目还有很多。这些题目如果不能拿分的话，给面试官的印象会很不好。这几次面试的时候，面试官手里一般都是我的笔试试卷 + 面试评分单。面试官都会拿我的基础题目说，为什么这道题目都不会？所以把握基础题目至关重要的。</p>
<p>　　计算机本身是门实践性更强的学科，所以如果平时不怎么编程，是很难发现自己的问题和未知的领域的。tencent的笔试题目考得很细很深，平时不上机code的同学可能很难会想到所考的知识点； 而遇到问题时不刨根问底或者得过且过，则会造成更大的遗憾。const char *和char * const的区别，内存的分配方式和管理方式，内存泄漏等等，平时感觉到有一丁点疑惑时，问题的背后一般藏有更多你不了解的；还有一点也很重要，像PPPOE并不是在书上，但是大家听说的就比较多了。应该及时的去了解这些前沿领域（虽然PPPOE不算前沿），保持对本专业发展方向的敏感，扩大自己的视野。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.boluor.com/2009-the-first-summary-of-writtens-and-interviews.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>基础&#8230;</title>
		<link>http://www.boluor.com/basic-notes.html</link>
		<comments>http://www.boluor.com/basic-notes.html#comments</comments>
		<pubDate>Sun, 25 Oct 2009 14:00:39 +0000</pubDate>
		<dc:creator>boluor</dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[日记]]></category>

		<guid isPermaLink="false">http://www.boluor.com/?p=410</guid>
		<description><![CDATA[<p>　　某题目：问下面的程序需要几次才能跳出循环？</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;">        <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> a <span style="color: #339933;">=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
        <span style="color: #993333;">int</span> b <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> a<span style="color: #339933;">+</span>b <span style="color: #339933;">&#62;=</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            b<span style="color: #339933;">--;</span>
        <span style="color: #009900;">&#125;</span></pre></div></div>

<p>　　开始以为a会转换为int类型，这样循环只需要2次就结束了。测试程序后发现这是个死循环。今天看《The C Programming Language》，赫然发现&#8221;转换&#8221;一节中，提到了&#8221;整数提升&#8221;一词。规定：在一个表达式中，如果原始类型的所有值都可以用int类型表示，则其值将被转换为int类型，否则将被转换为unsigned int类型。</p>
<p>　　我感觉很多时候我花了大把时间来搞明白，甚至以为&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>　　某题目：问下面的程序需要几次才能跳出循环？</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;">        <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> a <span style="color: #339933;">=</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
        <span style="color: #993333;">int</span> b <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> a<span style="color: #339933;">+</span>b <span style="color: #339933;">&gt;=</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            b<span style="color: #339933;">--;</span>
        <span style="color: #009900;">&#125;</span></pre></div></div>

<p>　　开始以为a会转换为int类型，这样循环只需要2次就结束了。测试程序后发现这是个死循环。今天看《The C Programming Language》，赫然发现&#8221;转换&#8221;一节中，提到了&#8221;整数提升&#8221;一词。规定：在一个表达式中，如果原始类型的所有值都可以用int类型表示，则其值将被转换为int类型，否则将被转换为unsigned int类型。</p>
<p>　　我感觉很多时候我花了大把时间来搞明白，甚至以为是很高深的问题，答案却明白的写在书上。书读百遍，其意自现，少开QQ多看书。　　</p>
<p>　　Sandy说你来试一题：不用sizeof如何知道机器是32位还是16位?<br />
<span id="more-410"></span><br />
　　想了很久后，我觉得还是从指针所占的空间入手。因为32位机器寻址，指针需要占4个字节，同理16位机器指针只需2个字节。于是想到如果给一个指针赋值在(max(16), max(32)]区间，那么16位机器应该会把高位截断，这样就可以区别开来。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;">	<span style="color: #993333;">char</span> <span style="color: #339933;">*</span>p<span style="color: #339933;">;</span>
	p <span style="color: #339933;">=</span> <span style="color: #208080;">0x10001</span><span style="color: #339933;">;</span><span style="color: #666666; font-style: italic;">//如果为16bit，那么最高位的1将被忽略。</span>
	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>p <span style="color: #339933;">==</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>
		<span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;16<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;">else</span>
		<span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;32<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>　　但是这种方法gcc给出了警告，Sandy说有的编译器都可能报Error。他的方法是：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;"><span style="color: #993333;">int</span> a<span style="color: #339933;">=</span><span style="color: #208080;">0xffff</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>a<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: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;16位&quot;</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>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;32位&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>　　中午从Church出来，和Father Wang一起去吃饭。碰到了几个他的外国朋友，他们聊得很开心，我愣在那里。突然有个过来跟我握手，然后&#8221;nice to meet you,i&#8217;m Tom&#8221;，我继续愣了下，才想起来要说什么。于是，开始把初中背熟的那几段抛出来，问候+自我介绍+天气。末了，他说&#8221;You speak English very well&#8221;，赶紧说&#8221;thank you&#8221;&#8230;这次不等他们过来了，直接过去跟他们一个个问候，结识了几个朋友。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.boluor.com/basic-notes.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>linux中使用命名管道实现客户端／服务器模型的进程间通信</title>
		<link>http://www.boluor.com/linux-cs-ipc-using-named-pipe.html</link>
		<comments>http://www.boluor.com/linux-cs-ipc-using-named-pipe.html#comments</comments>
		<pubDate>Sun, 16 Aug 2009 11:11:46 +0000</pubDate>
		<dc:creator>boluor</dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://www.boluor.com/?p=272</guid>
		<description><![CDATA[<p>　　Linux下进程间通信主要有管道，消息队列，信号量，共享内存，套接口。这里主要说命名管道的一个应用：使用命名管道实现进程间Server/Client机制的通信.</p>
<p>　　之所以去接触它，是因为实验室的项目中要求可信组和加密组可以进行通信。两者都在用户层，加密组向可信组发送请求，可信组返回响应。比如加密小组发送请求密钥信息，可信组返回所请求的密钥。由于传输的信息相对来说比较大,而且这两个程序逻辑上并不相关，所以在几种通信方式中我们选择了命名管道。</p>
<p>　　命名管道其实是FIFO文件。在linux中终端下创建一个管道,用mkfifo命令：mkfifo fifoname；或者mknod命令：mknod fifo&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>　　Linux下进程间通信主要有管道，消息队列，信号量，共享内存，套接口。这里主要说命名管道的一个应用：使用命名管道实现进程间Server/Client机制的通信.</p>
<p>　　之所以去接触它，是因为实验室的项目中要求可信组和加密组可以进行通信。两者都在用户层，加密组向可信组发送请求，可信组返回响应。比如加密小组发送请求密钥信息，可信组返回所请求的密钥。由于传输的信息相对来说比较大,而且这两个程序逻辑上并不相关，所以在几种通信方式中我们选择了命名管道。</p>
<p>　　命名管道其实是FIFO文件。在linux中终端下创建一个管道,用mkfifo命令：mkfifo fifoname；或者mknod命令：mknod fifoname p；最后的p表明该文件是个管道文件。<br />
<span id="more-272"></span></p>
<p>　　再说下访问FIFO文件。首先利用mkfifo命令创建一个管道文件：mkfifo /tmp/tmpfifo。然后读取其内容：cat /tmp/tmpfifo。可以发现这条命令没有结束，这是因为管道正在等待数据的写入。打开另一个终端，向管道写数据：echo &#8220;test&#8221; > /tmp/tmpfifo；此时两条命令都正常结束。读取端将打印出从管道中读取到的&#8221;test&#8221;。当然也可以将一端命令放在后台执行，比如读取时可以用：cat /tmp/tmpfifo &#038; ；(有关这方面的信息，可以查下几条命令：管理作业jobs，将任务放入后台bg，将程序放入前台fg，结束任务kill)。	上面的例子说明了，管道的一方(读取端或者写入端)在未得道另一方时，是一直被阻塞的，当然要想不被阻塞可以通过一些参数设定。在程序中，我们用open函数来打开管道。open函数的第一个参数即为管道文件路径，第二个参数为标志位。标志位有O_RDONLY，O_WRONLY，O_NONBLOCK，前两个参数可以和O_NONBLOCK配合使用，不过会改变open调用的处理方式。它们的作用从名字可以猜出来，O_RDONLY表明作为读取端，O_WRONLY表明作为写入端，O_NONBLOCK表示读取时不阻塞，也就是说这端立即检查管道中有没有数据，不论有没有都会立即返回，不会在没有数据时被阻塞。</p>
<p>　　现在来看如何利用FIFO实现进程间服务器/客户端的通信模式。首先，假设一个很简单的需求：客户端发送一串字符串，服务器将字符串翻转后返送给客户端。因为可能有不同的客户端同时发出请求，我们在回送管道名字中加入客户端进程的pid来标识。</p>
<p>　　首先，我们设计客户端和服务器端通信数据的结构和一些都会用到的系统头文件common.h。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;"><span style="color: #339933;">#include &quot;unistd.h&quot;</span>
<span style="color: #339933;">#include &quot;stdlib.h&quot;</span>
<span style="color: #339933;">#include &quot;stdio.h&quot;</span>
<span style="color: #339933;">#include &quot;string.h&quot;</span>
<span style="color: #339933;">#include &quot;fcntl.h&quot;</span>
<span style="color: #339933;">#include &quot;limits.h&quot;</span>
<span style="color: #339933;">#include &lt;sys/types.h&gt; </span>
<span style="color: #339933;">#include &lt;sys/stat.h&gt;</span>
<span style="color: #339933;">#include &quot;ctype.h&quot;</span>
<span style="color: #339933;">#define Server_FIFO_Name &quot;serv_fifo&quot;</span>
<span style="color: #339933;">#define Client_FIFO_Name &quot;client_%d_fifo&quot;</span>
&nbsp;
<span style="color: #339933;">#define BufSize 200</span>
&nbsp;
<span style="color: #993333;">struct</span> data_to_pass<span style="color: #009900;">&#123;</span>
	pid_t client_pid<span style="color: #339933;">;</span>	<span style="color: #666666; font-style: italic;">//保存客户端进程的PID。</span>
	<span style="color: #993333;">char</span> str<span style="color: #009900;">&#91;</span>BufSize<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></div></div>

<p>　　再来看服务器端。服务器端首先要建立管道以便其他进程向其发送数据，然后再打开回送管道，向客户端返回数据，然后再回到开始等待客户端向其请求数据。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;"><span style="color: #339933;">#include &quot;common.h&quot;</span>
<span style="color: #666666; font-style: italic;">//字符串翻转函数</span>
<span style="color: #993333;">void</span> reverse<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> str<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
	<span style="color: #993333;">int</span> len <span style="color: #339933;">=</span> strlen <span style="color: #009900;">&#40;</span>str<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #993333;">char</span> tmpc<span style="color: #339933;">;</span>
	<span style="color: #993333;">char</span> <span style="color: #339933;">*</span>h<span style="color: #339933;">,*</span>t<span style="color: #339933;">;</span>	
	h <span style="color: #339933;">=</span> str<span style="color: #339933;">;</span> t <span style="color: #339933;">=</span> str <span style="color: #339933;">+</span> <span style="color: #009900;">&#40;</span>len<span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span>h <span style="color: #339933;">&lt;</span> t<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>	<span style="color: #666666; font-style: italic;">//注意这里不能写成(h != t)</span>
		tmpc <span style="color: #339933;">=</span> <span style="color: #339933;">*</span>h<span style="color: #339933;">;</span>
		<span style="color: #339933;">*</span>h <span style="color: #339933;">=</span> <span style="color: #339933;">*</span>t<span style="color: #339933;">;</span>
		<span style="color: #339933;">*</span>t <span style="color: #339933;">=</span> tmpc<span style="color: #339933;">;</span>
&nbsp;
		h<span style="color: #339933;">++;</span>
		t<span style="color: #339933;">--;</span>
	<span style="color: #009900;">&#125;</span>	
<span style="color: #009900;">&#125;</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>
	<span style="color: #993333;">int</span> server_fifo_fd<span style="color: #339933;">,</span>client_fifo_fd<span style="color: #339933;">;</span>
	<span style="color: #993333;">struct</span> data_to_pass my_data<span style="color: #339933;">;</span>
	<span style="color: #993333;">int</span> read_res<span style="color: #339933;">;</span>
	<span style="color: #993333;">char</span> client_fifo<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: #993333;">char</span> <span style="color: #339933;">*</span>char_ptr<span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">//创建server管道。</span>
	mkfifo<span style="color: #009900;">&#40;</span>Server_FIFO_Name<span style="color: #339933;">,</span><span style="color: #208080;">0777</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
Again<span style="color: #339933;">:</span> 	<span style="color: #666666; font-style: italic;">//偷懒了，用goto去实现循环监听请求.</span>
	<span style="color: #666666; font-style: italic;">//打开服务器端口，等待读取。此时如果客户端还未写入数据服务器端会被阻塞。</span>
	server_fifo_fd <span style="color: #339933;">=</span> open<span style="color: #009900;">&#40;</span>Server_FIFO_Name <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> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span> <span style="color: #339933;">==</span> server_fifo_fd <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
		fprintf<span style="color: #009900;">&#40;</span> stderr <span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Server fifo failure<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		exit<span style="color: #009900;">&#40;</span>EXIT_FAILURE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #666666; font-style: italic;">//从管道中读取数据。	</span>
	read_res <span style="color: #339933;">=</span> read <span style="color: #009900;">&#40;</span> server_fifo_fd <span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>my_data <span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>my_data<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>read_res <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: #666666; font-style: italic;">//将字符串翻转.	</span>
		reverse <span style="color: #009900;">&#40;</span> my_data.<span style="color: #202020;">str</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>	
		<span style="color: #666666; font-style: italic;">//将客户端的pid号加入回送管道文件名中.	</span>
		sprintf <span style="color: #009900;">&#40;</span> client_fifo<span style="color: #339933;">,</span> Client_FIFO_Name <span style="color: #339933;">,</span> my_data.<span style="color: #202020;">client_pid</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #666666; font-style: italic;">//打开回送管道。	</span>
		client_fifo_fd <span style="color: #339933;">=</span> open <span style="color: #009900;">&#40;</span> client_fifo <span style="color: #339933;">,</span> O_WRONLY <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>	
		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span> <span style="color: #339933;">!=</span> client_fifo_fd <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
			<span style="color: #666666; font-style: italic;">//向管道中写入返回的数据.</span>
			write <span style="color: #009900;">&#40;</span> client_fifo_fd <span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>my_data<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>my_data<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>	
			close <span style="color: #009900;">&#40;</span> client_fifo_fd <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>	
	close<span style="color: #009900;">&#40;</span>server_fifo_fd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>	
&nbsp;
	<span style="color: #b1b100;">goto</span> Again<span style="color: #339933;">;</span>	
	unlink<span style="color: #009900;">&#40;</span>Server_FIFO_Name<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	exit<span style="color: #009900;">&#40;</span>EXIT_SUCCESS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>　　最后就是客户端，模式其实差不多。先打开服务器管道，发送数据，然后创建回送管道，等待服务器返回数据。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;"><span style="color: #339933;">#include &quot;common.h&quot;</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>
	<span style="color: #993333;">int</span> server_fifo_fd<span style="color: #339933;">,</span>client_fifo_fd<span style="color: #339933;">;</span>
	<span style="color: #993333;">struct</span> data_to_pass mydata<span style="color: #339933;">;</span>
	<span style="color: #993333;">int</span> times_to_send<span style="color: #339933;">;</span>
	<span style="color: #993333;">char</span> client_fifo<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: #993333;">int</span> rst<span style="color: #339933;">;</span>	
&nbsp;
	<span style="color: #666666; font-style: italic;">//打开服务器管道，开始写入.	采用NON_BLOCK方式，所以需要服务器先打开。</span>
	server_fifo_fd <span style="color: #339933;">=</span> open<span style="color: #009900;">&#40;</span>Server_FIFO_Name<span style="color: #339933;">,</span>O_WRONLY <span style="color: #339933;">|</span> NON_BLOCK<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>server_fifo_fd <span style="color: #339933;">==</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
		fprintf<span style="color: #009900;">&#40;</span>stderr <span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Sorry ,No Server<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		exit<span style="color: #009900;">&#40;</span>EXIT_FAILURE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #666666; font-style: italic;">//获得当前进程PID存入结构中。	</span>
	mydata.<span style="color: #202020;">client_pid</span> <span style="color: #339933;">=</span> getpid<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	sprintf <span style="color: #009900;">&#40;</span> client_fifo<span style="color: #339933;">,</span>Client_FIFO_Name <span style="color: #339933;">,</span>mydata.<span style="color: #202020;">client_pid</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>mkfifo<span style="color: #009900;">&#40;</span>client_fifo <span style="color: #339933;">,</span><span style="color: #208080;">0777</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
		fprintf<span style="color: #009900;">&#40;</span>stderr <span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Sorry ,can't make %s <span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span>client_fifo<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		exit<span style="color: #009900;">&#40;</span>EXIT_FAILURE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #666666; font-style: italic;">//填写发送的数据包.</span>
	sprintf<span style="color: #009900;">&#40;</span>mydata.<span style="color: #202020;">str</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot;%s&quot;</span><span style="color: #339933;">,</span><span style="color: #ff0000;">&quot;12345&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>		
&nbsp;
	<span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d sent %s,&quot;</span><span style="color: #339933;">,</span>mydata.<span style="color: #202020;">client_pid</span> <span style="color: #339933;">,</span> mydata.<span style="color: #202020;">str</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">//向管道中写入数据：发送.</span>
	write<span style="color: #009900;">&#40;</span>server_fifo_fd <span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>mydata <span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>mydata<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">//打开回送管道，等待接受从服务器返回的数据。	</span>
	client_fifo_fd <span style="color: #339933;">=</span> open<span style="color: #009900;">&#40;</span>client_fifo<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>client_fifo_fd <span style="color: #339933;">!=</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>	
		rst <span style="color: #339933;">=</span> read<span style="color: #009900;">&#40;</span> client_fifo_fd <span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>mydata <span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>mydata<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>			
		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> rst <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: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;received : %s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span>mydata.<span style="color: #202020;">str</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
		close<span style="color: #009900;">&#40;</span>client_fifo_fd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	close<span style="color: #009900;">&#40;</span>server_fifo_fd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	unlink<span style="color: #009900;">&#40;</span>client_fifo<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	exit<span style="color: #009900;">&#40;</span>EXIT_SUCCESS<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>　　至此，一个虽然简单但是比较完整的客户端服务器模式的进程间通信过程完成了。下面是在我机器上的运行效果。</p>
<blockquote><p>
boluor@boluor-laptop:~/programs/pipe/testpipe$ ./server &#038;<br />
[1] 30259<br />
boluor@boluor-laptop:~/programs/pipe/testpipe$ ./client<br />
30301 sent 12345,received : 54321<br />
boluor@boluor-laptop:~/programs/pipe/testpipe$ jobs<br />
[1]+  Running                 ./server &#038;<br />
boluor@boluor-laptop:~/programs/pipe/testpipe$ kill %1
</p></blockquote>
<p>　　至于和socket的比较，首先命名管道是面向连接的，而socket是无连接的；其次，他们都可以实现任意两个进程间的通信；再次，命名管道只是单向传输，要想实现双向必须另建立管道模拟实现。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.boluor.com/linux-cs-ipc-using-named-pipe.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>linux中fork小结</title>
		<link>http://www.boluor.com/summary-of-fork-in-linux.html</link>
		<comments>http://www.boluor.com/summary-of-fork-in-linux.html#comments</comments>
		<pubDate>Mon, 03 Aug 2009 16:05:16 +0000</pubDate>
		<dc:creator>boluor</dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://www.boluor.com/?p=223</guid>
		<description><![CDATA[<p>	fork函数在linux中非常重要,因为进程大多是通过它来创建的,比如linux系统在启动时首先创建了进程0,之后的很多进程借助do_fork得到创建.这两天在看匿名管道时了解了下fork,其应用毕竟广,这里只说些我才学到的吧.<br />
	首先来看例1.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;"><span style="color: #339933;">#include &#34;stdio.h&#34; </span>
<span style="color: #339933;">#include &#34;unistd.h&#34; </span>
<span style="color: #339933;">#include &#34;stdlib.h&#34; </span>
&#160;
<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> i<span style="color: #339933;">;</span> 
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&#34;hello world %d<span style="color: #000099; font-weight: bold;">\n</span>&#34;</span><span style="color: #339933;">,</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> 
    i<span style="color: #339933;">=</span></pre></div></div><p>&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>	fork函数在linux中非常重要,因为进程大多是通过它来创建的,比如linux系统在启动时首先创建了进程0,之后的很多进程借助do_fork得到创建.这两天在看匿名管道时了解了下fork,其应用毕竟广,这里只说些我才学到的吧.<br />
	首先来看例1.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;"><span style="color: #339933;">#include &quot;stdio.h&quot; </span>
<span style="color: #339933;">#include &quot;unistd.h&quot; </span>
<span style="color: #339933;">#include &quot;stdlib.h&quot; </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> 
    <span style="color: #993333;">int</span> i<span style="color: #339933;">;</span> 
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;hello world %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</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> 
    i<span style="color: #339933;">=</span><span style="color: #0000dd;">3</span><span style="color: #339933;">;</span> 
    fork<span style="color: #009900;">&#40;</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;var %d in  %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span>i<span style="color: #339933;">,</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> 
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> 
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>	输出是什么呢?<br />
	这是在我的机器上一次执行的结果:</p>
<blockquote><p>
hello world 8168<br />
var 3 in  8169<br />
var 3 in  8168
</p></blockquote>
<p>	为什么会有两次输出var 3 一行呢?看似不可思议吧&#8230;要解释原因,就牵涉到了我们要讨论的fork,它到底做了什么?<br />
<span id="more-223"></span><br />
	fork英文是叉的意思.在这里的意思是进程从这里开始分叉,分成了两个进程,一个是父进程,一个子进程.子进程拷贝了父进程的绝大部分.栈阿,缓冲区阿等等.系统为子进程创建一个新的进程表项,其中进程id与父进程是不相同的,这也就是说父子进程是两个独立的进程,虽然父子进程共享代码空间.但是在牵涉到写数据时子进程有自己的数据空间,这是因为copy on write机制,在有数据修改时,系统会为子进程申请新的页面.</p>
<p>	再来复习下进程的有关知识.系统通过进程控制块PCB来管理进程.进程的执行,可以看作是在它的上下文中执行.一个进程的上下文(context)由三部分组成：用户级上下文,寄存器上下文和系统级上下文.用户级上下文中有正文,数据,用户栈和共享存储区;寄存器上下文中有个非常重要的程序计数器(传说中的)PC,还有栈指针和通用寄存器等;系统级上下文分静态和动态,PCB中进程表项,U区,还有本进程的表项,页表,系统区表项等都属于静态部分,而核心栈等则属于动态部分.</p>
<p>	回到fork上来.fork在内核中对应的是do_fork函数,本来想自己写下函数说明的,发现已经有了.详见：<a href="http://blog.sina.com.cn/s/blog_4b9216f50100cwwu.html###">内核 do_fork 函数源代码浅析</a>	. 上面已经提到,fork后,子进程拷贝了父进程的进程表项,还有栈阿,缓冲区,U区等等.当然在这之前会去检查系统有没有可用的资源,取一个空闲的进程表项和唯一的PID号等工作.(后面的例子会体现子进程到底拷贝了父进程的哪些东西.)需要指出的是,这里所说的拷贝,并不是说子进程再申请页面,将父进程中的全部拷贝过来.而是,他们共享一个空间,子进程只是作一层映射而已,这个时候进程页面标记为只读.在有数据修改时,才会申请新的页面,拷贝过来,并标记为可写.</p>
<p>	fork执行后,对父进程和子进程不同的地方还有,对父进程返回子进程的pid号,对子进程返回的是0.大致的算法描述为:</p>
<blockquote><p>
if (当前正在执行的是父进程){<br />
	将子进程的状态设置为&#8221;就绪状态&#8221;;<br />
	return (子进程的pid号);<br />
}else{	/*正在执行的是子进程*/<br />
	初始化U区等工作;<br />
	return 0;<br />
}
</p></blockquote>
<p>	现在来看例1,是不是已经清晰了很多? 在执行了fork之后,父子进程分别都执行了下一步printf语句.由于fork拷贝走了pc,所以在子进程中不会再从main入口重新执行,而是执行fork后的下一条指令.而i是保存在进程栈空间中的,所以子进程中也存在.<br />
	有了前面的基础,再看下面一个例2:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
<span style="color: #339933;">#include &lt;unistd.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> i<span style="color: #339933;">=</span><span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
    pid_t fork_result<span style="color: #339933;">;</span>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;pid : %d --&gt; main begin()<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</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>
&nbsp;
    fork_result <span style="color: #339933;">=</span> fork<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>fork_result <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: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Fork Failure<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>
    <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><span style="color: #0000dd;">3</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: #b1b100;">if</span><span style="color: #009900;">&#40;</span>fork_result <span style="color: #339933;">==</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;">//在子进程中.</span>
            <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;child process : %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><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: #b1b100;">else</span><span style="color: #009900;">&#123;</span>
            <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Father process : %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><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>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>	这次输出可以更明确的显示出子进程到底拷贝了些什么.我机器上的两次执行结果:</p>
<blockquote><p>
boluor@boluor-laptop:~/programs/pipe/fork$ ./a.out<br />
pid : 16567 &#8211;> main begin()<br />
child process : 0<br />
child process : 1<br />
child process : 2<br />
Father process : 0<br />
Father process : 1<br />
Father process : 2<br />
boluor@boluor-laptop:~/programs/pipe/fork$ ./a.out<br />
pid : 16569 &#8211;> main begin()<br />
Father process : 0<br />
Father process : 1<br />
Father process : 2<br />
child process : 0<br />
child process : 1<br />
child process : 2
</p></blockquote>
<p>	同时也可以说明,父子进程到底哪个先执行,是跟cpu调度有关系的.如果想固定顺序,那么就要用wait或vfork函数.<br />
	继续看例3：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;"><span style="color: #339933;">#include &quot;stdio.h&quot;</span>
<span style="color: #339933;">#include &quot;unistd.h&quot;</span>
<span style="color: #339933;">#include &quot;stdlib.h&quot;</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>
    <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;hello world %d&quot;</span><span style="color: #339933;">,</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>
    <span style="color: #666666; font-style: italic;">//fflush(0);</span>
    fork<span style="color: #009900;">&#40;</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></div></div>

<p>	执行上面的程序,可以发现输出了两遍hello world.而且两次的pid号都是一样的.这是为什么呢? 这其实是因为printf的行缓冲的问题,printf语句执行后,系统将字符串放在了缓冲区内,并没有输出到stdout.不明白的话看下面的例子:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;"><span style="color: #339933;">#include &quot;stdio.h&quot;</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: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;hello world&quot;</span><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: #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></div></div>

<p>	执行上面的程序你会发现,程序陷入死循环,并没有输出&#8221;hello world&#8221;.这就是因为把&#8221;hello world&#8221;放入了缓冲区.我们平常加&#8217;\n&#8217;的话,就会刷新缓冲区,那样就会直接输出到stdout了.</p>
<p>	因为子进程将这些缓冲也拷贝走了,所以子进程也打印了一遍.父进程直到最后才输出.他们的输出是一样的,输出的pid是一致的,因为子进程拷贝走的是printf语句执行后的结果.如果利用setbuf设置下,或者在printf语句后调用fflush(0);强制刷新缓冲区,就不会有这个问题了.这个例子从侧面显示出子进程也拷贝了父进程的缓冲区.</p>
<p>	关于fork的应用还很多很多,在实际项目中需要了再去深入研究.关于fork和exec的区别,exec是将本进程的映像给替换掉了,跟fork差别还是很大的,其实fork创建子进程后,大部分情况下,子进程会调用exec去执行不同的程序的.</p>
<p>	先说到这里了.如果需要更多fork的知识就google一下^.^.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.boluor.com/summary-of-fork-in-linux.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>linux内核模块之间通信</title>
		<link>http://www.boluor.com/communication-between-the-kernel-module-of-linux.html</link>
		<comments>http://www.boluor.com/communication-between-the-kernel-module-of-linux.html#comments</comments>
		<pubDate>Wed, 29 Jul 2009 18:11:42 +0000</pubDate>
		<dc:creator>boluor</dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[linux kernel]]></category>

		<guid isPermaLink="false">http://www.boluor.com/?p=217</guid>
		<description><![CDATA[<p>    今天师兄问，linux内核模块之间如何进行通信？我才想起我之前也有这个疑问，只是当时不需要所以就没去关心了。晚上查了些资料，终于弄明白了些。<br />
    这里的通信可以简单点理解，就是模块B如何调用A的函数，变量或者常量。为了简化，我设计一个模块A中的一个函数为printMSG，原型为int printMSG(int n);传入的参数n表示打印几遍一个固定的字符串。模块A(在helloworld基础上修改的，所以名字都没变&#8230;懒)源码：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;"><span style="color: #339933;">#include &#60;linux/init.h&#62; </span>
<span style="color: #339933;">#include &#60;linux/module.h&#62;  </span>
<span style="color: #993333;">int</span> __init hello_init<span style="color: #009900;">&#40;</span><span style="color: #993333;">vo</span></pre></div></div><p>&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>    今天师兄问，linux内核模块之间如何进行通信？我才想起我之前也有这个疑问，只是当时不需要所以就没去关心了。晚上查了些资料，终于弄明白了些。<br />
    这里的通信可以简单点理解，就是模块B如何调用A的函数，变量或者常量。为了简化，我设计一个模块A中的一个函数为printMSG，原型为int printMSG(int n);传入的参数n表示打印几遍一个固定的字符串。模块A(在helloworld基础上修改的，所以名字都没变&#8230;懒)源码：</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;"><span style="color: #339933;">#include &lt;linux/init.h&gt; </span>
<span style="color: #339933;">#include &lt;linux/module.h&gt;  </span>
<span style="color: #993333;">int</span> __init hello_init<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> 
    printk<span style="color: #009900;">&#40;</span>KERN_ALERT <span style="color: #ff0000;">&quot;hello world
&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> 
&nbsp;
<span style="color: #993333;">int</span> printMSG<span style="color: #009900;">&#40;</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> i<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>n<span style="color: #339933;">;</span>i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> 
        printk<span style="color: #009900;">&#40;</span>KERN_ALERT <span style="color: #ff0000;">&quot;I am boluor
&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> 
&nbsp;
<span style="color: #993333;">void</span> __exit hello_exit<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> 
    printk<span style="color: #009900;">&#40;</span>KERN_ALERT <span style="color: #ff0000;">&quot;byebye,hello world
&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
<span style="color: #009900;">&#125;</span> 
EXPORT_SYMBOL<span style="color: #009900;">&#40;</span>printMSG<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
module_init<span style="color: #009900;">&#40;</span>hello_init<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 
module_exit<span style="color: #009900;">&#40;</span>hello_exit<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p><span id="more-217"></span><br />
    其中用到了EXPORT_SYMBOL宏来表明导出printMSG这个符号。还有一个EXPORT_SYMBOL_GPL宏，导出的符号具有GPL授权。内核所有的导出符号可以通过 : cat /proc/kallsyms来查看，太多了，所以最好导出到一个文件中慢慢看。在其中就可以发现printk等等我们常见的内核函数。</p>
<p>    现在我们写一个测试模块B，他将调用A中的printMSG函数。B的源码和A大致一样，这里只给出不同的地方吧。</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:Courier new,verdana;"><span style="color: #000000; font-weight: bold;">extern</span> <span style="color: #993333;">int</span> printMSG<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> n<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  <span style="color: #666666; font-style: italic;">//声明printMSG来自外部文件.</span>
<span style="color: #993333;">int</span> __init test_init<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: #666666; font-style: italic;">//在模块加载的时候调用.</span>
    printk<span style="color: #009900;">&#40;</span>KERN_ALERT <span style="color: #ff0000;">&quot;hello world
&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    printMSG<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>    两个模块的Makefile文件参照<a href="http://www.boluor.com/?p=86">Linux设备驱动学习笔记</a>.编译通过后，先insmod 模块A，再insmod B，就可以发现B可以插入了。查看log，通过dmesg | tail -10就可以发现B在加载的时候输出了三行&#8221;I am boluor&#8221;。<br />
    通过以上的测试，对linux所谓的LKM有了更深的认识。内核其实就是一个大的程序，当我们动态的加载进入一个模块时，他还是内核这个大程序的一部分，所以我们可以像一个工程中那样，将函数导出到内核符号表中，再将需要调用的外部的函数声明为extern关键字，就可以方便的调用了。</p>
<p>     从回来到现在，搜了很多资料，抄来抄去的，都没说明到底怎么作，问题依旧没有答案。在CSDN上看到一帖，也說得这问题，中有人说，需要使用系统调用。。。不知道怎么想的，反正测试没通过。这些还是得靠不断的去试，才会有正确的结果。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.boluor.com/communication-between-the-kernel-module-of-linux.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>键盘钩子函数执行两次解决方法</title>
		<link>http://www.boluor.com/solution-to-the-keyboard-hook-function-is-executed-twice.html</link>
		<comments>http://www.boluor.com/solution-to-the-keyboard-hook-function-is-executed-twice.html#comments</comments>
		<pubDate>Mon, 06 Jul 2009 09:31:03 +0000</pubDate>
		<dc:creator>boluor</dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[hook]]></category>
		<category><![CDATA[VC]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://www.boluor.com/?p=169</guid>
		<description><![CDATA[<p>考虑下面的键盘钩子函数。(MFC工程)</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="cpp" style="font-family:Courier new,verdana;">LRESULT CALLBACK KeyProc<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> nCode,WPARAM w,LPARAM l<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
	<span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">'A'</span><span style="color: #000080;">==</span>w<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
		MessageBox<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">NULL</span>,<span style="color: #FF0000;">&#34;yes&#34;</span>,<span style="color: #FF0000;">&#34;test&#34;</span>,MB_OK<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
		<span style="color: #0000ff;">return</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
	<span style="color: #008000;">&#125;</span>
&#160;
	<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>    也就是想在按下A的时候，弹出一个对话框。</p>
<p>     然后在一个事件中添加：<br />
     SetWindowsHookEx(WH_KEYBOARD,KeyProc,NULL,GetCurrentThread&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>考虑下面的键盘钩子函数。(MFC工程)</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="cpp" style="font-family:Courier new,verdana;">LRESULT CALLBACK KeyProc<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> nCode,WPARAM w,LPARAM l<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
	<span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">'A'</span><span style="color: #000080;">==</span>w<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
		MessageBox<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">NULL</span>,<span style="color: #FF0000;">&quot;yes&quot;</span>,<span style="color: #FF0000;">&quot;test&quot;</span>,MB_OK<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
		<span style="color: #0000ff;">return</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
	<span style="color: #008000;">&#125;</span>
&nbsp;
	<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>    也就是想在按下A的时候，弹出一个对话框。</p>
<p>     然后在一个事件中添加：<br />
     SetWindowsHookEx(WH_KEYBOARD,KeyProc,NULL,GetCurrentThreadId());<br />
    安装钩子。事件被触发后，就可以调用上面的键盘钩子函数了。</p>
<p>    但是在执行时会发现，当按下A时，提示框弹出了两遍。是什么原因呢？<br />
<span id="more-169"></span><br />
     想到了一个解释，那就是当按键时，按下和弹起分别是一个事件，所以调用了两次钩子函数。那么如何解决呢？看MSDN的帮助时发现，KeyboardProc Function的第三个参数，也就是LPARAM类型的参数，有很多的作用。LAPRAM占4个字节，32位。每一位都是一个特殊的标志。比如说如果Alt键被按下的话，第29位就是1，否则为0。那么键盘按下和弹起是哪个呢？是第30位。这一位标记了上次按键的状态。在消息发送之前，如果按键是按下的，那么值为1，否则为0。(经Sandy提醒,添加下面一句)第31位标记当前按键的状态，取值和第30位的规则相同。我们可以根据这一位来过滤掉按下和弹起中的一个。<br />
     添加一层过滤后，代码如下：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre class="cpp" style="font-family:Courier new,verdana;">LRESULT CALLBACK KeyProc<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> nCode,WPARAM w,LPARAM l<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
	<span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>l  <span style="color: #000080;">&gt;&gt;</span> <span style="color: #0000dd;">31</span> <span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>	<span style="color: #666666;">//修改前为第30位，应该是第31位，判断当前按键状态。</span>
		<span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">'A'</span><span style="color: #000080;">==</span>w<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
			MessageBox<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">NULL</span>,<span style="color: #FF0000;">&quot;yes&quot;</span>,<span style="color: #FF0000;">&quot;test&quot;</span>,MB_OK<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
			<span style="color: #0000ff;">return</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
		<span style="color: #008000;">&#125;</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>	 那么为什么我之前用第30位来判断也是可以的呢? 原因在于，当前按键时，第30位也就是保存了上次按键的状态位必定为弹起状态，那么上面的语句也就可以正常执行。不过，每次判断的都不是当前按键的状态，而是上次的状态。这在其他应用中会造成很难察觉的错误。(谢谢Sandy的提醒，以后多点细心^.^)。</p>
<p>     其实系统提供了一个预定义KF_UP，在winuser.h中，来标记按键是否是弹起状态。不过，使用时需要注意，如果这样判断：<br />
     if ( l &#038; KF_UP){<br />
             //key up<br />
     }<br />
     是不正确的。注意在KF_UP定义的地方有一句：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="cpp" style="font-family:Courier new,verdana;"> <span style="color: #ff0000; font-style: italic;">/*
 * WM_KEYUP/DOWN/CHAR HIWORD(lParam) flags
 */</span>
<span style="color: #339900;">#define KF_UP             0x8000</span></pre></td></tr></table></div>

<p>      这表明，KF_UP是高位标志。使用时需要移位。所以可以这样比较：<br />
      if ( KF_UP &#038; ( l >> 16 ) ){<br />
      }<br />
      或者利用宏HIWORD取得参数l的高16位。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.boluor.com/solution-to-the-keyboard-hook-function-is-executed-twice.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>C语言中实现模板函数小结</title>
		<link>http://www.boluor.com/summary-about-template-function-under-c.html</link>
		<comments>http://www.boluor.com/summary-about-template-function-under-c.html#comments</comments>
		<pubDate>Tue, 19 May 2009 17:25:00 +0000</pubDate>
		<dc:creator>boluor</dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://www.boluor.com/?p=81</guid>
		<description><![CDATA[<p>	&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#8212;-by boluor 2009/5/20<br />
	&#160;&#160;&#160;&#160;&#160;&#160;如果要写个函数支持多种数据类型，首先想到的就是C++的模板了，但是有时候只能用C语言，比如在linux内核开发中，为了减少代码量，或者是某面试官的要求…<br />
	&#160;&#160;&#160;&#038;&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8212;-by boluor 2009/5/20<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果要写个函数支持多种数据类型，首先想到的就是C++的模板了，但是有时候只能用C语言，比如在linux内核开发中，为了减少代码量，或者是某面试官的要求…<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;考虑了一阵子后，就想到了qsort上.qsort的函数原型：<br />
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;快排时，只要自己实现相应数据类型的比较函数cmpare就可以了.如果比较int型时,一个典型的compare函数如下：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:Courier new,verdana;"><span style="color: #0000ff;">int</span> cmp<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>a,<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>b<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>a<span style="color: #008000;">&#41;</span><span style="color: #000040;">-*</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>b<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p><span id="more-81"></span></p>
<p>	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;那么,就是说可以利用void *. void *意指未指定类型，也可以理解为任意类型。其他类型的指针可以直接赋值给void *变量，但是void *变量需要强制类型转换为其它指针类型。这个相信大家都知道。那么下面以一个简单的题目为例，来探讨如何在C语言中实现模板函数。<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>方法1</strong>：	利用void *.<br />
		&nbsp;&nbsp;&nbsp;&nbsp;在看下面的源程序之前，需要了解几点。首先，在32位平台上，任何类型的指针所占的字节都是4个字节，因为32位机器虚拟内存一般为4G，即2的32次方，只要32位即4个字节就可以足够寻址，sizeof(void *)=4；	其次，虽然各种不同类型的指针所占的空间都为4个字节，但是不同类型的指针所指的空间的字节数却不同(这一点尤为重要，下面的程序我在开始没有调通就因为这点意识不强)。所以，如果你将一个指针强制转换为另一个类型的指针，指针本身所占的字节是不变的，但是，如果对这个指针进行运算，比如 *p,p++,p-=1等一般都是不同的。	再次，函数指针应该了解下，这里不多说。	最后，因为Sandy跟我说，C++开始的时候模板的实现其实就是利用宏替换，在编译的时候确定类型。所以，为了方便，类型也用了预编译指令#define。</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:Courier new,verdana;"><span style="color: #339900;">#include &quot;stdio.h&quot;</span>
<span style="color: #339900;">#include &quot;stdlib.h&quot;</span>
&nbsp;
<span style="color: #666666;">//typedef int T;  //或者下面的也可以.</span>
<span style="color: #339900;">#define  T int</span>
&nbsp;
<span style="color: #0000ff;">int</span> cmp<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>a,<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>b<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>T <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>a<span style="color: #008000;">&#41;</span><span style="color: #000040;">-*</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>T <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>b<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #ff0000; font-style: italic;">/*
//这个FindMin是Sandy写的.felix021也写了个,差不多的就不贴出来的.
void FindMin(const void  *arr,int arr_size,int arrmembersize,int *index,    
             int (*cmp)(const void *,const void *b)){
    int i;
	*index=0;
	char *p=(char *)arr;
	char *tmp=p;
    for (i=1;i&lt;arr_size ;i++){
        if (cmp(tmp,p)&gt;0){
            tmp=p;
        }
		p+=arrmembersize;
    }
	(*index)=((int)(tmp-arr))/arrmembersize;
}
*/</span>
&nbsp;
<span style="color: #0000ff;">int</span> FindMin<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>arr,<span style="color: #0000ff;">int</span> arr_size,<span style="color: #0000ff;">int</span> arrmembersize,<span style="color: #0000ff;">int</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>cmp<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>,<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
	<span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>p<span style="color: #000080;">=</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>arr<span style="color: #008080;">;</span>	<span style="color: #666666;">//可以把指针看作是char *,如果转换为int *,那下面的位移就不正确了.</span>
	<span style="color: #0000ff;">int</span> index<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
	<span style="color: #0000ff;">int</span> i<span style="color: #008080;">;</span>
	<span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span>i<span style="color: #000080;">=</span><span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>i<span style="color: #000080;">&lt;</span><span style="color: #000040;">/</span>arr_size<span style="color: #000080;">&gt;&lt;</span>arr_size <span style="color: #008080;">;</span><span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
		<span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>cmp<span style="color: #008000;">&#40;</span>p<span style="color: #000040;">+</span>index<span style="color: #000040;">*</span>arrmembersize,p<span style="color: #000040;">+</span>i<span style="color: #000040;">*</span>arrmembersize<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: #008000;">&#123;</span>
			index<span style="color: #000080;">=</span>i<span style="color: #008080;">;</span>
		<span style="color: #008000;">&#125;</span>
	<span style="color: #008000;">&#125;</span>
&nbsp;
	<span style="color: #0000ff;">return</span> index<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
&nbsp;
&nbsp;
<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>
    <span style="color: #0000ff;">int</span> arr<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #000080;">=</span><span style="color: #008000;">&#123;</span><span style="color: #0000dd;">2</span>,<span style="color: #0000dd;">1</span>,<span style="color: #0000dd;">1</span>,<span style="color: #0000dd;">2</span>,<span style="color: #0000dd;">3</span>,<span style="color: #0000dd;">4</span>,<span style="color: #0000dd;">5</span>,<span style="color: #0000dd;">0</span>,<span style="color: #0000dd;">2</span>,<span style="color: #0000dd;">3</span>,<span style="color: #0000dd;">1</span>,<span style="color: #0000dd;">3</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
    <span style="color: #666666;">//int *result;</span>
    <span style="color: #0000ff;">int</span> result<span style="color: #008080;">;</span><span style="color: #666666;">//result保存的是最小值索引.</span>
    result<span style="color: #000080;">=</span>FindMin<span style="color: #008000;">&#40;</span>arr,<span style="color: #0000dd;">12</span>,<span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>arr<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span>,cmp<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;%d,%d
&quot;</span>,result,arr<span style="color: #008000;">&#91;</span>result<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
	<span style="color: #0000dd;">system</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;PAUSE&quot;</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></div></div>

<p>	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>方法2</strong>：利用宏。在编译的时候确定类型。查阅资料的时候，很多都说这种方法比较好，方便调试，也很直观，虽然很啰嗦。</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:Courier new,verdana;"><span style="color: #339900;">#include &lt;stdio .h&gt;</span>
&nbsp;
<span style="color: #339900;">#ifndef _INT_</span>
<span style="color: #339900;">#define _INT_</span>
<span style="color: #339900;">#endif</span>
&nbsp;
<span style="color: #0000ff;">int</span> cmp<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>a,<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>b<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>    
    <span style="color: #339900;">#ifdef _INT_</span>
        <span style="color: #0000ff;">return</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>a<span style="color: #000040;">-*</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>b<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #339900;">#elif _FLOAT_</span>
        <span style="color: #0000ff;">return</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">fabs</span><span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">float</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>a<span style="color: #000040;">-*</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">float</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>b<span style="color: #008000;">&#41;</span><span style="color: #000040;">&amp;</span>lt<span style="color: #008080;">;</span><span style="color:#800080;">1e-6</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">?</span><span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008080;">:</span><span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
    <span style="color: #339900;">#elif _DOUBLE_</span>
        <span style="color: #0000ff;">return</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">fabs</span><span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">double</span> <span style="color: #000040;">*</span>a<span style="color: #008000;">&#41;</span><span style="color: #000040;">-*</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">double</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>b<span style="color: #008000;">&#41;</span><span style="color: #000040;">&amp;</span>lt<span style="color: #008080;">;</span><span style="color:#800080;">1e-9</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">?</span><span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008080;">:</span><span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
    <span style="color: #339900;">#endif</span>
<span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #339900;">#ifdef _INT_</span>
<span style="color: #0000ff;">void</span> FindMin<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span>arr,<span style="color: #0000ff;">int</span> arr_size,<span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span>result,<span style="color: #0000ff;">int</span> cmp<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>a,<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>b<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
<span style="color: #339900;">#elif _FLOAT_</span>
<span style="color: #0000ff;">void</span>  FindMin<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">float</span> <span style="color: #000040;">*</span>arr,<span style="color: #0000ff;">int</span> arr_size,<span style="color: #0000ff;">float</span> <span style="color: #000040;">*</span>result,<span style="color: #0000ff;">int</span> cmp<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>a,<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>b<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
<span style="color: #339900;">#elif _DOUBLE_</span>
<span style="color: #0000ff;">void</span>  FindMin<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">double</span> <span style="color: #000040;">*</span>arr,<span style="color: #0000ff;">int</span> arr_size,<span style="color: #0000ff;">double</span> <span style="color: #000040;">*</span>result,<span style="color: #0000ff;">int</span> cmp<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>a,<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>b<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
<span style="color: #339900;">#endif</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span> i<span style="color: #008080;">;</span>
    <span style="color: #000040;">*</span>result<span style="color: #000080;">=</span>arr<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>    
    <span style="color: #0000ff;">for</span><span style="color: #008000;">&#40;</span>i<span style="color: #000080;">=</span><span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>i<span style="color: #000080;">&lt;</span>arr_size <span style="color: #008080;">;</span><span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>cmp<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>arr<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span>,result<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: #000040;">*</span>result<span style="color: #000080;">=</span>arr<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span>
&nbsp;
<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>
    <span style="color: #0000ff;">int</span> arr1<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #000080;">=</span><span style="color: #008000;">&#123;</span><span style="color: #0000dd;">1</span>,<span style="color: #0000dd;">2</span>,<span style="color: #0000dd;">4</span>,<span style="color: #0000dd;">2</span>,<span style="color: #0000dd;">1</span>,<span style="color: #0000dd;">7</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> result<span style="color: #008080;">;</span>
    FindMin<span style="color: #008000;">&#40;</span>arr1,<span style="color: #0000dd;">6</span>,<span style="color: #000040;">&amp;</span>result,cmp<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
&quot;</span>,result<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></div></div>

<p>	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>方法3</strong>：在findmin中，不用强制类型转换为char *，直接利用memcpy内存拷贝过去，这时，还可以在参数列表中保存结果，而不是索引。此方法由CSDN上的ltc_mouse提供。</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:Courier new,verdana;"><span style="color: #339900;">#include &quot;stdio.h&quot;</span>
<span style="color: #339900;">#include &quot;stdlib.h&quot;</span>
<span style="color: #339900;">#include &quot;string.h&quot;</span>
&nbsp;
<span style="color: #0000ff;">void</span> FindMin<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>arr,<span style="color: #0000ff;">int</span> arr_size,<span style="color: #0000ff;">int</span> arrmembersize,<span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span> result,
             <span style="color: #0000ff;">int</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>fpCmp<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>,<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>b<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span> i<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>pSrc <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>arr<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>pRes <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>result<span style="color: #008080;">;</span>
    <span style="color: #0000dd;">memcpy</span><span style="color: #008000;">&#40;</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>pRes, <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>pSrc, arrmembersize <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span>i<span style="color: #000080;">=</span><span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>i<span style="color: #000080;">&lt;</span><span style="color: #000040;">/</span>arr_size<span style="color: #000080;">&gt;&lt;</span>arr_size <span style="color: #008080;">;</span>i<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
        pSrc <span style="color: #000040;">+</span><span style="color: #000080;">=</span> arrmembersize<span style="color: #008080;">;</span>
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span> fpCmp<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>pSrc, result<span style="color: #008000;">&#41;</span><span style="color: #000040;">&amp;</span>lt<span style="color: #008080;">;</span><span style="color: #0000dd;">0</span> <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: #008000;">&#40;</span><span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>pRes, <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>pSrc, arrmembersize <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">int</span> cmp_int<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>a, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>b<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #008000;">&#40;</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>a <span style="color: #000040;">-</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>b <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">int</span> cmp_double<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>a, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>b<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #008000;">&#40;</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">fabs</span><span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">double</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>a <span style="color: #000080;">&lt;</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">double</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>b <span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #000040;">&amp;</span>lt<span style="color: #008080;">;</span><span style="color:#800080;">1e-9</span><span style="color: #008000;">&#41;</span> <span style="color: #008080;">?</span> <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span> <span style="color: #008080;">:</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span> <span style="color: #666666;">//这个可能要调整下</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>
    <span style="color: #0000ff;">int</span> iArr<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #000080;">=</span><span style="color: #008000;">&#123;</span><span style="color: #0000dd;">1</span>,<span style="color: #0000dd;">3</span>,<span style="color: #0000dd;">5</span>,<span style="color: #000040;">-</span><span style="color: #0000dd;">1</span>,<span style="color: #0000dd;">3</span>,<span style="color: #0000dd;">4</span>,<span style="color: #0000dd;">7</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">double</span> fArr<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #000080;">=</span><span style="color: #008000;">&#123;</span><span style="color: #000040;">-</span><span style="color:#800080;">3.2</span>, <span style="color:#800080;">2.3</span>, <span style="color:#800080;">7.8</span>, <span style="color: #000040;">-</span><span style="color:#800080;">9.3</span>, <span style="color:#800080;">4.7</span>, <span style="color:#800080;">10.5</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> iMin<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">double</span> fMin<span style="color: #008080;">;</span>
    FindMin<span style="color: #008000;">&#40;</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>iArr, <span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>iArr<span style="color: #008000;">&#41;</span><span style="color: #000040;">/</span><span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>iArr<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>iArr<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #000040;">&amp;</span>iMin, cmp_int <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    FindMin<span style="color: #008000;">&#40;</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>fArr, <span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>fArr<span style="color: #008000;">&#41;</span><span style="color: #000040;">/</span><span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>fArr<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>fArr<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #000040;">&amp;</span>fMin, cmp_double<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;Min of iArr is %d
&quot;</span>, iMin<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;Min of fArr is %lf
&quot;</span>, fMin<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></div></div>

<p>参考资料：<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.<a href="http://topic.csdn.net/u/20090518/23/b814d421-0a88-4292-9743-a7036c3a6dce.html" target="_blank">CSDN上的讨论帖.<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.<a href="http://blog.csdn.net/whinah/archive/2004/06/16/13815.aspx" target="_blank">在C中实现函数模板的方法</a>.</p>
<p>后记：<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;感谢所有帮助解决这个问题了朋友！这问题纠结了我两天，通过这个感觉对指针的理解又多了一点。<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CSDN上的hikaliv建议看下va_list,va_args等看下可变参数如何读取,顺便理解了下，其实之前Sandy跟我说过，只是一直没看，现在看了感觉收获蛮大。Felix021说我的代码风格不好，开始不明白，不过等他和Sandy写出来他们写的FindMin后，就明白了，我的代码太晦涩了，还是写个自己看的，别人看了看不出大概，真的多注意了。<br />
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;虽然，在C语言中实现模板不是不可能，但是我还是倾向于用模板，C++我了解的太少了。</arr_size></stdio></arr_size></p>
]]></content:encoded>
			<wfw:commentRss>http://www.boluor.com/summary-about-template-function-under-c.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>在VS2005中添加lib库</title>
		<link>http://www.boluor.com/add-lib-library-under-visual-studio-2005.html</link>
		<comments>http://www.boluor.com/add-lib-library-under-visual-studio-2005.html#comments</comments>
		<pubDate>Wed, 13 May 2009 08:38:00 +0000</pubDate>
		<dc:creator>boluor</dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://www.boluor.com/blog/?p=68</guid>
		<description><![CDATA[<p>&#160;&#160;&#160;&#160;&#160;&#160; 晚上写一个程序的时候，用到了EnumProcesses函数，这个函数是platform sdk中的。包含了,”psapi.h”后，还是提示找不到这个EnumProcesses。后来Sandy说这些并不需要包含的，因为这些是平台所有的。用vs2005，我去目录下搜，发现了那个psapi.h(VCPlatformSDKInclude)，在VC6中都没发现的。以为可以编译成功了，没想直接提示了一堆莫名其妙的错误，提示在psapi.h中语法错误? 这怎么可能? </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160; 还是&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>&#160;&#160;&#160;&#160;&#160;&#160; 晚上写一个程序的时候，用到了EnumProcesses函数，这个函数是platform sdk中的。包含了<windows .h>,”psapi.h”后，还是提示找不到这个EnumProcesses。后来Sandy说这些并不需要包含的，因为这些是平台所有的。用vs2005，我去目录下搜，发现了那个psapi.h(VCPlatformSDKInclude)，在VC6中都没发现的。以为可以编译成功了，没想直接提示了一堆莫名其妙的错误，提示在psapi.h中语法错误? 这怎么可能? </windows></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160; 还是Sandy最后试出来，加了一句,#pragma comment(lib,”psapi.lib”)后编译通过了。后来想如果能够手动设置项目就不用每次添加了。在网上找到了解决方法：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160; 在工程—项目属性中，找到Linker节点，如果是只设置对本项目有效，就在Input子节点中的Additional Dependence中添加自己需要的Lib库，比如我需要psapi.lib。如果要对所有的配置添加lib库文件，那么在general子节点中，对additional library directories中添加lib库所在的目录即可。 </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160; 参考：<a href="http://www.cnblogs.com/alexusli/archive/2009/01/07/1370976.html#1527398" target="_blank">参考文献</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.boluor.com/add-lib-library-under-visual-studio-2005.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>DLL基础</title>
		<link>http://www.boluor.com/dll-base.html</link>
		<comments>http://www.boluor.com/dll-base.html#comments</comments>
		<pubDate>Mon, 11 May 2009 05:15:00 +0000</pubDate>
		<dc:creator>boluor</dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[DLL]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://www.boluor.com/blog/?p=60</guid>
		<description><![CDATA[<p>&#160;&#160;&#160;&#160;&#160;&#160; 想写个程序,可以监控某个进程,然后对其进行某些操作…别怀疑我的动机，我是和谐社会的良民<img alt="" src="http://www.zu14.cn/coolemotion/emotions/hi_6.gif" /> </p>
<p>然后第一步开始，DLL到底是什么?听到DLLl这词的次数绝对比我的年龄大（本人年方22，嘿嘿！），不过却从来没去研究过，所以一直觉得DLL很神秘。不过，箭在弦上，不得不去了解了。想找本书看的，结果搜罗了半个小时没发现，烦了，就开始看<a href="http://hi.baidu.com/44997/blog/item/dcf47b59198b2d2a2934f0e1.html">某人的blog</a>，实现了后觉得豁然开朗啊。微软官网的<a href="http://support.microsoft.com/kb/815065/zh-cn">帮助</a>也不错。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; 原文写的很不错。写下我的感受。</p>
<p>【<strong>概念</strong>】</p>
<p>&#160;&#160;&#038;&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>&#160;&#160;&#160;&#160;&#160;&#160; 想写个程序,可以监控某个进程,然后对其进行某些操作…别怀疑我的动机，我是和谐社会的良民<img alt="" src="http://www.zu14.cn/coolemotion/emotions/hi_6.gif" /> </p>
<p>然后第一步开始，DLL到底是什么?听到DLLl这词的次数绝对比我的年龄大（本人年方22，嘿嘿！），不过却从来没去研究过，所以一直觉得DLL很神秘。不过，箭在弦上，不得不去了解了。想找本书看的，结果搜罗了半个小时没发现，烦了，就开始看<a href="http://hi.baidu.com/44997/blog/item/dcf47b59198b2d2a2934f0e1.html">某人的blog</a>，实现了后觉得豁然开朗啊。微软官网的<a href="http://support.microsoft.com/kb/815065/zh-cn">帮助</a>也不错。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; 原文写的很不错。写下我的感受。</p>
<p>【<strong>概念</strong>】</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; DLL是动态链接库的缩写，是一个包含有可使多个程序同时使用的数据和代码。使用促进代码的模块化、代码重用、内存的有效使用和减少所占用的磁盘空间。不过，由于使用DLL的程序需要实时的调用DLL中的数据或者代码，所以DLL必须和软件一起发放。</p>
<p> <span id="more-60"></span>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; DLL是建立在客户/服务器通信的概念上，包含若干函数、类或资源的库文件，函数和数据被存储在一个DLL（服务器）上并由一个或多个客户导出而使用，这些客户可以是应用程序或者是其它的DLL。DLL库不同于静态库，在静态库情况下，函数和数据被编译进一个二进制文件（通常扩展名为*.LIB），Visual C++的编译器在处理程序代码时将从静态库中恢复这些函数和数据并把他们和应用程序中的其他模块组合在一起生成可执行文件。这个过程称为&quot;静态链接&quot;，此时因为应用程序所需的全部内容都是从库中复制了出来，所以静态库本身并不需要与可执行文件一起发行。      <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 在动态库的情况下，有两个文件，一个是引入库（.LIB）文件，一个是DLL文件，引入库文件包含被DLL导出的函数的名称和位置，DLL包含实际的函数和数据，应用程序使用LIB文件链接到所需要使用的DLL文件，库中的函数和数据并不复制到可执行文件中，因此在应用程序的可执行文件中，存放的不是被调用的函数代码，而是DLL中所要调用的函数的内存地址，这样当一个或多个应用程序运行是再把程序代码和被调用的函数代码链接起来，从而节省了内存资源。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 微软的Visual C++支持三种DLL，它们分别是Non-MFC Dll（非MFC动态库）、Regular Dll（常规DLL）、Extension Dll（扩展DLL）。Non-MFC DLL指的是不用MFC的类库结构，直接用C语言写的DLL，其导出的函数是标准的C接口，能被非MFC或MFC编写的应用程序所调用。Regular DLL:和下述的Extension Dlls一样，是用MFC类库编写的，它的一个明显的特点是在源文件里有一个继承CWinApp的类（注意：此类DLL虽然从CWinApp派生，但没有消息循环）,被导出的函数是C函数、C++类或者C++成员函数（注意不要把术语C++类与MFC的微软基础C++类相混淆），调用常规DLL的应用程序不必是MFC应用程序，只要是能调用类C函数的应用程序就可以，它们可以是在Visual C++、Dephi、Visual Basic、Borland C等编译环境下利用DLL开发应用程序。</p>
<p>【<strong>编程基础</strong>】(以下多为引用)</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 由VS6或者VS2005时创建DLL工程只要按照提示一步步就行了。这里都是以VS2005，Non-MFC DLL。</p>
<p><strong>Win32 Dynamic-Link Library方式创建Non-MFC DLL动态链接库：</strong></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 每一个DLL都必须有一个入口函数，默认是DllMain，这跟C里的main函数类似。用这个确省的入口函数就可以对DLL正确的初始化。典型的格式如下：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:Courier new,verdana;">BOOL APIENTRY DllMain<span style="color: #008000;">&#40;</span> HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 <span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
	<span style="color: #0000ff;">switch</span> <span style="color: #008000;">&#40;</span>ul_reason_for_call<span style="color: #008000;">&#41;</span>
	<span style="color: #008000;">&#123;</span>
	<span style="color: #0000ff;">case</span> DLL_PROCESS_ATTACH<span style="color: #008080;">:</span>
	<span style="color: #0000ff;">case</span> DLL_THREAD_ATTACH<span style="color: #008080;">:</span>
	<span style="color: #0000ff;">case</span> DLL_THREAD_DETACH<span style="color: #008080;">:</span>
	<span style="color: #0000ff;">case</span> DLL_PROCESS_DETACH<span style="color: #008080;">:</span>
		<span style="color: #0000ff;">break</span><span style="color: #008080;">;</span>
	<span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">return</span> TRUE<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 对于进程线程的创建和释放时,需要进行的操作在case时调用就可以了。</p>
<p><strong>导出DLL中的Symbols</strong></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; DLL是包含若干个函数的库文件，应用程序使用DLL中的函数之前，应该先导出这些函数，以便供给应用程序使用。要导出这些函数有两种方法，一是在定义函数时使用导出关键字__declspec(dllexport)，另外一种方法是在创建DLL文件时使用模块定义文件.Def。需要注意的是在使用第一种方法的时候，不能使用DEF文件。例子看附件。</p>
<ol>
<li>&#160;&#160;&#160;&#160;&#160; 使用__declspec(dllexport)来创建mydll.dll。该动态链接库中有两个函数，分别用来实现得到两个数的最大和最小数。在MyDll.h和MyDLL.cpp文件中分别输入如下原代码：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:Courier new,verdana;"><span style="color: #666666;">//MyDll.h</span>
<span style="color: #0000ff;">extern</span> <span style="color: #FF0000;">&quot;C&quot;</span> __declspec<span style="color: #008000;">&#40;</span>dllexport<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">int</span> Max<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: #008080;">;</span>
<span style="color: #0000ff;">extern</span> <span style="color: #FF0000;">&quot;C&quot;</span> __declspec<span style="color: #008000;">&#40;</span>dllexport<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">int</span> Min<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: #008080;">;</span>
<span style="color: #666666;">//MyDll.cpp</span>
<span style="color: #0000ff;">int</span> Max<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: #000080;">&gt;</span>b<span style="color: #008080;">?</span>a<span style="color: #008080;">:</span>b<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">int</span> Min<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: #000080;">&gt;</span>b<span style="color: #008080;">?</span>b<span style="color: #008080;">:</span>a<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>  &#160;&#160;&#160;&#160;&#160; 该动态链接库编译成功后，打开MyDll工程中的debug目录，可以看到MyDll.dll、MyDll.lib两个文件。LIB文件中包含DLL文件名和DLL文件中的函数名等，该LIB文件只是对应该DLL文件的&quot;映像文件&quot;，与DLL文件中，LIB文件的长度要小的多，在进行隐式链接DLL时要用到它。读者可能已经注意到在MyDll.h中有关键字&quot;extern C&quot;，它可以使其他编程语言访问你编写的DLL中的函数。 </li>
<li>&#160;&#160;&#160;&#160; 用.def文件来创建DLL。        <br />&#160;&#160; 为了用.def文件创建DLL，请先删除上个例子创建的工程中的MyDll.h文件，保留MyDll.cpp并在该文件头删除#include MyDll.h语句，同时往该工程中加入一个文本文件，命名为MyDll.def，再在该文件中加入如下代码：         <br />LIBRARY MyDll         <br />EXPORTS         <br />Max         <br />Min         <br />其中LIBRARY语句说明该def文件是属于相应DLL的，EXPORTS语句下列出要导出的函数名称。我们可以在.def文件中的导出函数后加 @n，如Max@1，Min@2，表示要导出的函数顺序号，在进行显式连时可以用到它。该DLL编译成功后，打开工程中的Debug目录，同样也会看到 MyDll.dll和MyDll.lib文件。 </li>
</ol>
<p>&#160;</p>
<p><strong>动态链接库DLL的链接 </strong>      <br />&#160;&#160;&#160;&#160;&#160; 应用程序使用DLL可以采用两种方式：一种是隐式链接，另一种是显式链接。在使用DLL之前首先要知道DLL中函数的结构信息。Visual C++安装目录下提供了一个名为Dumpbin.exe的小程序，用它可以查看DLL文件中的函数结构。另外，Windows系统将遵循下面的搜索顺序来定位DLL： 1．包含EXE文件的目录，2．进程的当前工作目录， 3．Windows系统目录， 4．Windows目录，5．列在Path环境变量中的一系列目录。&#160; <br />1．隐式链接       <br />&#160;&#160;&#160;&#160;&#160; 隐式链接就是在程序开始执行时就将DLL文件加载到应用程序当中。实现隐式链接很容易，只要将导入函数关键字 __declspec(dllimport)函数名等写到应用程序相应的头文件中就可以了。下面的例子通过隐式链接调用MyDll.dll库中的Min函数。首先生成一个项目为TestDll，在DllTest.h、DllTest.cpp文件中分别输入如下代码：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:Courier new,verdana;"><span style="color: #666666;">//DllTest.h</span>
<span style="color: #666666;">//dll1.dll生成时用的def文件，不是用头文件生成的。</span>
<span style="color: #339900;">#pragma comment(lib,&quot;dll1.lib&quot;)  </span>
<span style="color: #666666;">//如果生成DLL时使用了头文件，下面的声明和头文件的要相对应。</span>
<span style="color: #666666;">//比如在最前面加 extern &quot;C&quot;</span>
__declspec<span style="color: #008000;">&#40;</span>dllimport<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">int</span> Max<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: #008080;">;</span> 
__declspec<span style="color: #008000;">&#40;</span>dllimport<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">int</span> Min<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: #008080;">;</span>  
<span style="color: #666666;">//DllTest.cpp</span>
<span style="color: #339900;">#include &lt;iostream&gt;</span>
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
&nbsp;
<span style="color: #339900;">#include &quot;testdll.h&quot;</span>
&nbsp;
<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>
&nbsp;
	<span style="color: #0000ff;">int</span> a,b<span style="color: #008080;">;</span>
	<span style="color: #0000ff;">while</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">cin</span><span style="color: #000080;">&gt;&gt;</span>a<span style="color: #000080;">&gt;&gt;</span>b<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span>
		<span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;</span> <span style="color: #000080;">&lt;</span><span style="color: #FF0000;">&quot;较大数:&quot;</span> <span style="color: #000080;">&lt;&lt;</span> Max<span style="color: #008000;">&#40;</span>a,b<span style="color: #008000;">&#41;</span><span style="color: #000080;">&lt;&lt;</span>endl<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></div></div>

<p>    在创建DllTest.exe文件之前，要先将MyDll.dll和MyDll.lib拷贝到当前工程所在的目录下面，也可以拷贝到windows的 System目录下。如果DLL使用的是def文件，要删除TestDll.h文件中关键字extern &quot;C&quot;。TestDll.h文件中的关键字Progam commit是要Visual C+的编译器在link时，链接到MyDll.lib文件，当然，开发人员也可以不使用#pragma comment(lib,&#8221;dll1.lib&#8221;)语句，而直接在工程的Setting-&gt;Link页的Object/Moduls栏填入 MyDll.lib既可。 </p>
<p>2．显式链接&#160; <br />&#160;&#160;&#160;&#160;&#160; 显式链接是应用程序在执行过程中随时可以加载DLL文件，也可以随时卸载DLL文件，这是隐式链接所无法作到的，所以显式链接具有更好的灵活性，对于解释性语言更为合适。不过实现显式链接要麻烦一些。在应用程序中用LoadLibrary或MFC提供的AfxLoadLibrary显式的将自己所做的动态链接库调进来，动态链接库的文件名即是上述两个函数的参数，此后再用GetProcAddress()获取想要引入的函数。自此，你就可以象使用如同在应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之前，应该用FreeLibrary或MFC提供的AfxFreeLibrary释放动态链接库。下面是通过显式链接调用DLL中的Max函数的例子。</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:Courier new,verdana;"><span style="color: #0000ff;">void</span> main<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;">typedef</span> <span style="color: #0000ff;">int</span><span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>pMax<span style="color: #008000;">&#41;</span><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: #008080;">;</span>
	<span style="color: #0000ff;">typedef</span> <span style="color: #0000ff;">int</span><span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>pMin<span style="color: #008000;">&#41;</span><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: #008080;">;</span>
	HINSTANCE hDLL<span style="color: #008080;">;</span>
	PMax Max<span style="color: #008080;">;</span>
	HDLL<span style="color: #000080;">=</span>LoadLibrary<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;MyDll.dll&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><span style="color: #666666;">//加载动态链接库MyDll.dll文件；</span>
	Max<span style="color: #000080;">=</span><span style="color: #008000;">&#40;</span>pMax<span style="color: #008000;">&#41;</span>GetProcAddress<span style="color: #008000;">&#40;</span>hDLL,<span style="color: #FF0000;">&quot;Max&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
	A<span style="color: #000080;">=</span>Max<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">5</span>,<span style="color: #0000dd;">8</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
	Printf<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;比较的结果为%d&quot;</span>,a<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
	FreeLibrary<span style="color: #008000;">&#40;</span>hDLL<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><span style="color: #666666;">//卸载MyDll.dll文件；</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>&#160;&#160;&#160;&#160;&#160;&#160; 在上例中使用类型定义关键字typedef，定义指向和DLL中相同的函数原型指针，然后通过LoadLibray()将DLL加载到当前的应用程序中并返回当前DLL文件的句柄，然后通过GetProcAddress()函数获取导入到应用程序中的函数指针，函数调用完毕后，使用 FreeLibrary()卸载DLL文件。在编译程序之前，首先要将DLL文件拷贝到工程所在的目录或Windows系统目录下。       <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; 使用显式链接应用程序编译时不需要使用相应的Lib文件。另外，使用GetProcAddress()函数时，可以利用 MAKEINTRESOURCE()函数直接使用DLL中函数出现的顺序号，如将GetProcAddress(hDLL,&quot;Min&quot;)改为 GetProcAddress(hDLL, MAKEINTRESOURCE(2))（函数Min()在DLL中的顺序号是2），这样调用DLL中的函数速度很快，但是要记住函数的使用序号，否则会发生错误。</iostream></p>
]]></content:encoded>
			<wfw:commentRss>http://www.boluor.com/dll-base.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
