﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-开心就好-文章分类-C++</title><link>http://www.cppblog.com/shaovie/category/2725.html</link><description>做最好的自己</description><language>zh-cn</language><lastBuildDate>Fri, 23 May 2008 19:05:16 GMT</lastBuildDate><pubDate>Fri, 23 May 2008 19:05:16 GMT</pubDate><ttl>60</ttl><item><title>另类比较字符串的算法</title><link>http://www.cppblog.com/shaovie/articles/16385.html</link><dc:creator>崔少伟</dc:creator><author>崔少伟</author><pubDate>Wed, 13 Dec 2006 11:30:00 GMT</pubDate><guid>http://www.cppblog.com/shaovie/articles/16385.html</guid><wfw:comment>http://www.cppblog.com/shaovie/comments/16385.html</wfw:comment><comments>http://www.cppblog.com/shaovie/articles/16385.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaovie/comments/commentRss/16385.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaovie/services/trackbacks/16385.html</trackback:ping><description><![CDATA[
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">char p[] </span>
				<span style="COLOR: #000000">=</span>
				<span style="COLOR: #000000"> </span>
				<span style="FONT-WEIGHT: bold; COLOR: #000000">"</span>
				<span style="FONT-WEIGHT: bold; COLOR: #000000">HTTP</span>
				<span style="FONT-WEIGHT: bold; COLOR: #000000">"</span>
				<span style="COLOR: #000000">;<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />       <br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">if</span>
				<span style="COLOR: #000000">(</span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">(unsigned long </span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">)p </span>
				<span style="COLOR: #000000">!=</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">(unsigned long </span>
				<span style="COLOR: #000000">*</span>
				<span style="COLOR: #000000">)</span>
				<span style="FONT-WEIGHT: bold; COLOR: #000000">"</span>
				<span style="FONT-WEIGHT: bold; COLOR: #000000">HTTP</span>
				<span style="FONT-WEIGHT: bold; COLOR: #000000">"</span>
				<span style="COLOR: #000000">)<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />        {<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />            </span>
				<span style="COLOR: #0000ff">printf</span>
				<span style="COLOR: #000000">(</span>
				<span style="FONT-WEIGHT: bold; COLOR: #000000">"</span>
				<span style="FONT-WEIGHT: bold; COLOR: #000000">error!\n</span>
				<span style="FONT-WEIGHT: bold; COLOR: #000000">"</span>
				<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />        }<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">else</span>
				<span style="COLOR: #000000">
						<br />
						<img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />        {<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />                </span>
				<span style="COLOR: #0000ff">printf</span>
				<span style="COLOR: #000000">(</span>
				<span style="FONT-WEIGHT: bold; COLOR: #000000">"</span>
				<span style="FONT-WEIGHT: bold; COLOR: #000000">right!\n</span>
				<span style="FONT-WEIGHT: bold; COLOR: #000000">"</span>
				<span style="COLOR: #000000">);<br /><img src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align="top" />        }</span>
		</div>只适合固定字符串的长度..如果字符串长度超过usigned long 的字节数就不行了.<br />不过很高效的<img src ="http://www.cppblog.com/shaovie/aggbug/16385.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaovie/" target="_blank">崔少伟</a> 2006-12-13 19:30 <a href="http://www.cppblog.com/shaovie/articles/16385.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>16道嵌入式Ｃ语言面试题 </title><link>http://www.cppblog.com/shaovie/articles/15710.html</link><dc:creator>崔少伟</dc:creator><author>崔少伟</author><pubDate>Tue, 28 Nov 2006 00:39:00 GMT</pubDate><guid>http://www.cppblog.com/shaovie/articles/15710.html</guid><wfw:comment>http://www.cppblog.com/shaovie/comments/15710.html</wfw:comment><comments>http://www.cppblog.com/shaovie/articles/15710.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaovie/comments/commentRss/15710.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaovie/services/trackbacks/15710.html</trackback:ping><description><![CDATA[
		<font color="#003366">预处理器（Preprocessor）<br />1. 用预处理指令#define 声明一个常数，用以表明1年中有多少秒（忽略闰年问题）<br />    #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL  <br />    我在这想看到几件事情： <br />    1). #define 语法的基本知识（例如：不能以分号结束，括号的使用，等等） <br />    2). 懂得预处理器将为你计算常数表达式的值，因此，直接写出你是如何计算一年中<br />有多少秒而不是计算出实际的值，是更清晰而没有代价的。 <br />    3). 意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编<br />译器这个常数是的长整型数。 <br />   4). 如果你在你的表达式中用到UL（表示无符号长整型），那么你有了一个好的起点。<br />记住，第一印象很重要。<br /><br />2. 写一个“标准”宏MIN，这个宏输入两个参数并返回较小的一个。<br />#define MIN(A,B) ((A) &lt;= (B) (A) : (B)) <br />这个</font>
		<nobr>
				<a class="iAs" oncontextmenu="return false;" onmousemove="kwM(9);" onmouseover="kwE(event,9);" style="CURSOR: hand; COLOR: #0000ff; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" onclick="window.open('http://211.100.30.165/search/?key=测试','_blank');" onmouseout="kwL(event);" target="_blank">测试</a>
		</nobr>
		<font color="#003366">是为下面的目的而设的： <br />1). 标识#define在宏中应用的基本知识。这是很重要的，因为直到嵌入(inline)操作符变<br />为标准C的一部分，宏是方便产生嵌入代码的唯一方法，对于嵌入式系统来说，为了能达到<br />要求的性能，嵌入代码经常是必须的方法。 <br />2). 三重条件操作符的知识。这个操作符存在C语言中的原因是它使得编译器能产生比if-<br />then-else更优化的代码，了解这个用法是很重要的。 <br />3). 懂得在宏中小心地把参数用括号括起来 <br />4). 我也用这个问题开始讨论宏的副作用，例如：当你写下面的代码时会发生什么事？ <br /><br />least = MIN(*p++, b);<br /><br />3. 预处理器标识#error的目的是什么？<br /><br />如果你不知道答案，请看参考文献1。这问题对区分一个正常的伙计和一个书呆子是很有用<br />的。只有书呆子才会读C语言课本的附录去找出象这种 <br />问题的答案。当然如果你不是在找一个书呆子，那么应试者最好希望自己不要知道答案。<br /><br /><br />死循环（Infinite loops）<br /><br />4. 嵌入式系统中经常要用到无限循环，你怎么样用C编写死循环呢？<br /><br />这个问题用几个解决方案。我首选的方案是： <br />while(1) <br />{ <br />} <br />一些程序员更喜欢如下方案： <br />for(;;) <br />{ <br />} <br />这个实现方式让我为难，因为这个语法没有确切表达到底怎么回事。如果一个应试者给出<br />这个作为方案，我将用这个作为一个机会去探究他们这样做的 <br />基本原理。如果他们的基本答案是：“我被教着这样做，但从没有想到过为什么。”这会<br />给我留下一个坏印象。 <br />第三个方案是用 goto <br />Loop: <br />... <br />goto Loop; <br />应试者如给出上面的方案，这说明或者他是一个汇编语言程序员（这也许是好事）或者他<br />是一个想进入新领域的BASIC/FORTRAN程序员。<br /><br />数据声明（Data declarations） <br /><br />5. 用变量a给出下面的定义 <br />a) 一个整型数（An integer） <br />b) 一个指向整型数的指针（A pointer to an integer） <br />c) 一个指向指针的的指针，它指向的指针是指向一个整型数（A pointer to a pointer <br />to an integer） <br />d) 一个有10个整型数的数组（An array of 10 integers） <br />e) 一个有10个指针的数组，该指针是指向一个整型数的（An array of 10 pointers to <br />integers） <br />f) 一个指向有10个整型数数组的指针（A pointer to an array of 10 integers） <br />g) 一个指向函数的指针，该函数有一个整型参数并返回一个整型数（A pointer to a fu<br />nction that takes an integer as an argument and returns an integer） <br />h) 一个有10个指针的数组，该指针指向一个函数，该函数有一个整型参数并返回一个整型<br />数（ An array of ten pointers to functions that take an integer argument and r<br />eturn an integer ）<br /><br />答案是： <br />a) int a; // An integer <br />b) int *a; // A pointer to an integer <br />c) int **a; // A pointer to a pointer to an integer <br />d) int a[10]; // An array of 10 integers <br />e) int *a[10]; // An array of 10 pointers to integers <br />f) int (*a)[10]; // A pointer to an array of 10 integers <br />g) int (*a)(int); // A pointer to a function a that takes an integer argument <br />and returns an integer <br />h) int (*a[10])(int); // An array of 10 pointers to functions that take an int<br />eger argument and return an integer <br /><br />人们经常声称这里有几个问题是那种要翻一下书才能回答的问题，我同意这种说法。当我<br />写这篇文章时，为了确定语法的正确性，我的确查了一下书。 <br />但是当我被面试的时候，我期望被问到这个问题（或者相近的问题）。因为在被面试的这<br />段时间里，我确定我知道这个问题的答案。应试者如果不知道 <br />所有的答案（或至少大部分答案），那么也就没有为这次面试做准备，如果该面试者没有<br />为这次面试做准备，那么他又能为什么出准备呢？<br /><br />Static<br /><br />6. 关键字static的作用是什么？<br /><br />这个简单的问题很少有人能回答完全。在C语言中，关键字static有三个明显的作用： <br />1). 在函数体，一个被声明为静态的变量在这一函数被调用过程中维持其值不变。 <br />2). 在模块内（但在函数体外），一个被声明为静态的变量可以被模块内所用函数访问，<br />但不能被模块外其它函数访问。它是一个本地的全局变量。 <br />3). 在模块内，一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是，这<br />个函数被限制在声明它的模块的本地范围内使用。 <br />大多数应试者能正确回答第一部分，一部分能正确回答第二部分，同是很少的人能懂得第<br />三部分。这是一个应试者的严重的缺点，因为他显然不懂得本地化数据和代码范围的好处<br />和重要性。<br /><br />Const <br /><br />7．关键字const是什么含意？ <br />我只要一听到被面试者说：“const意味着常数”，我就知道我正在和一个业余者打交道。<br />去年Dan Saks已经在他的文章里完全概括了const的所有用法，因此ESP(译者：Embedded <br />Systems Programming)的每一位读者应该非常熟悉const能做什么和不能做什么.如果你从<br />没有读到那篇文章，只要能说出const意味着“只读”就可以了。尽管这个答案不是完全的<br />答案，但我接受它作为一个正确的答案。（如果你想知道更详细的答案，仔细读一下Saks<br />的文章吧。）如果应试者能正确回答这个问题，我将问他一个附加的问题：下面的声明都<br />是什么意思？<br /><br />const int a; <br />int const a; <br />const int *a; <br />int * const a; <br />int const * a const;<br /><br />前两个的作用是一样，a是一个常整型数。第三个意味着a是一个指向常整型数的指针（也<br />就是，整型数是不可修改的，但指针可以）。第四个意思a是一个指向整型数的常指针（也<br />就是说，指针指向的整型数是可以修改的，但指针是不可修改的）。最后一个意味着a是一<br />个指向常整型数的常指针（也就是说，指针指向的整型数是不可修改的，同时指针也是不<br />可修改的）。如果应试者能正确回答这些问题，那么他就给我留下了一个好印象。顺带提<br />一句，也许你可能会问，即使不用关键字const，也还是能很容易写出功能正确的程序，那<br />么我为什么还要如此看重关键字const呢？我也如下的几下理由： <br />1). 关键字const的作用是为给读你代码的人传达非常有用的信息，实际上，声明一个参数<br />为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃<br />圾，你就会很快学会感谢这点多余的信息。（当然，懂得用const的程序员很少会留下的垃<br />圾让别人来清理的。） <br />2). 通过给优化器一些附加的信息，使用关键字const也许能产生更紧凑的代码。 <br />3). 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数，防止其<br />被无意的代码修改。简而言之，这样可以减少bug的出现。<br /><br />Volatile <br /><br />8. 关键字volatile有什么含意 并给出三个不同的例子。<br /><br />一个定义为volatile的变量是说这变量可能会被意想不到地改变，这样，编译器就不会去<br />假设这个变量的值了。精确地说就是，优化器在用到这个变量时必须每次都小心地重新读<br />取这个变量的值，而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子：<br /><br />1). 并行设备的</font>
		<nobr>
				<a class="iAs" oncontextmenu="return false;" onmousemove="kwM(7);" onmouseover="kwE(event,7);" style="CURSOR: hand; COLOR: #0000ff; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" onclick="window.open('http://211.100.30.165/search/?key=硬件','_blank');" onmouseout="kwL(event);" target="_blank">硬件</a>
		</nobr>
		<font color="#003366">寄存器（如：状态寄存器） <br />2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) <br />3). 多线程应用中被几个任务共享的变量 <br />回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最<br />基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道，所用这些都要求vo<br />latile变量。不懂得volatile内容将会带来灾难。 <br />假设被面试者正确地回答了这是问题（嗯，怀疑这否会是这样），我将稍微深究一下，看<br />一下这家伙是不是直正懂得volatile完全的重要性。 <br />1). 一个参数既可以是const还可以是volatile吗？解释为什么。 <br />2). 一个指针可以是volatile 吗？解释为什么。 <br />3). 下面的函数有什么错误： <br />int square(volatile int *ptr) <br />{ <br />return *ptr * *ptr; <br />} <br />下面是答案： <br />1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。<br />它是const因为程序不应该试图去修改它。 <br />2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer<br />的指针时。 <br />3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方，但是，由<br />于*ptr指向一个volatile型参数，编译器将产生类似下面的代码： <br />int square(volatile int *ptr) <br />{ <br />int a,b; <br />a = *ptr; <br />b = *ptr; <br />return a * b; <br />} <br />由于*ptr的值可能被意想不到地该变，因此a和b可能是不同的。结果，这段代码可能返不<br />是你所期望的平方值！正确的代码如下： <br />long square(volatile int *ptr) <br />{ <br />int a; <br />a = *ptr; <br />return a * a; <br />}<br /><br />位操作（Bit manipulation）<br /><br />9. 嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量a，写两段代码<br />，第一个设置a的bit 3，第二个清除a 的bit 3。在以上两个操作中，要保持其它位不变。<br /><br /><br />对这个问题有三种基本的反应 <br />1). 不知道如何下手。该被面者从没做过任何嵌入式系统的工作。 <br />2). 用bit fields。Bit fields是被扔到C语言死角的东西，它保证你的代码在不同编译器<br />之间是不可移植的，同时也保证了的你的代码是不可重用的。我最近不幸看到Infineon为<br />其较复杂的</font>
		<nobr>
				<a class="iAs" oncontextmenu="return false;" onmousemove="kwM(4);" onmouseover="kwE(event,4);" style="CURSOR: hand; COLOR: #0000ff; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" onclick="window.open('http://211.100.30.165/search/?key=通信','_blank');" onmouseout="kwL(event);" target="_blank">通信</a>
		</nobr>
		<font color="#003366">芯片写的驱动程序，它用到了bit fields因此完全对我无用，因为我的编<br />译器用其它的方式来实现bit fields的。从道德讲：永远不要让一个非嵌入式的家伙粘实<br />际硬件的边。 <br />3). 用 #defines 和 bit masks 操作。这是一个有极高可移植性的方法，是应该被用到的<br />方法。最佳的解决方案如下： <br />#define BIT3 (0x1&lt;&lt;3) <br />static int a; <br />void set_bit3(void) <br />{ <br />a |= BIT3; <br />} <br />void clear_bit3(void) <br />{ <br />a &amp;= ~BIT3; <br />} <br />一些人喜欢为设置和清除值而定义一个掩码同时定义一些说明常数，这也是可以接受的。<br />我希望看到几个要点：说明常数、|=和&amp;=~操作。<br /><br />访问固定的内存位置（Accessing fixed memory locations） <br /><br />10. 嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中，要求<br />设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写<br />代码去完成这一任务。<br />这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换（typecast）为一指<br />针是合法的。这一问题的实现方式随着个人风格不同而不同。典型的类似代码如下： <br />int *ptr; <br />ptr = (int *)0x67a9; <br />*ptr = 0xaa55;<br /><br />一个较晦涩的方法是： <br />*(int * const)(0x67a9) = 0xaa55;<br />即使你的</font>
		<nobr>
				<a class="iAs" oncontextmenu="return false;" onmousemove="kwM(8);" onmouseover="kwE(event,8);" style="CURSOR: hand; COLOR: #0000ff; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" onclick="window.open('http://211.100.30.165/search/?key=品味','_blank');" onmouseout="kwL(event);" target="_blank">品味</a>
		</nobr>
		<font color="#003366">更接近第二种方案，但我建议你在面试时使用第一种方案。<br /><br />中断（Interrupts） <br /><br />11. 中断是嵌入式系统中重要的组成部分，这导致了很多编译开发商提供一种扩展—让标<br />准C支持中断。具代表事实是，产生了一个新的关键字__interrupt。下面的代码就使用了<br />__interrupt关键字去定义了一个中断服务子程序(ISR)，请评论一下这段代码的。<br />__interrupt double compute_area (double radius) <br />{ <br />double area = PI * radius * radius; <br />printf(" Area = %f", area); <br />return area; <br />}<br /><br />这个函数有太多的错误了，以至让人不知从何说起了： <br />1). ISR 不能返回一个值。如果你不懂这个，那么你不会被雇用的。 <br />2). ISR 不能传递参数。如果你没有看到这一点，你被雇用的机会等同第一项。 <br />3). 在许多的处理器/编译器中，浮点一般都是不可重入的。有些处理器/编译器需要让额<br />处的寄存器入栈，有些处理器/编译器就是不允许在ISR中做浮点运算。此外，ISR应该是短<br />而有效率的，在ISR中做浮点运算是不明智的。 <br />4). 与第三点一脉相承，printf()经常有重入和性能上的问题。如果你丢掉了第三和第四<br />点，我不会太为难你的。不用说，如果你能得到后两点，那么你的被雇用前景越来越光明<br />了。<br /><br />代码例子（Code examples）<br /><br />12 . 下面的代码输出是什么，为什么？<br />void foo(void) <br />{ <br />unsigned int a = 6; <br />int b = -20; <br />(a+b &gt; 6) puts("&gt; 6") : puts("&lt;= 6"); <br />}<br /><br />这个问题测试你是否懂得C语言中的整数自动转换原则，我发现有些开发者懂得极少这些东<br />西。不管如何，这无符号整型问题的答案是输出是“&gt;6”。原因是当表达式中存在有符号<br />类型和无符号类型时所有的操作数都自动转换为无符号类型。 因此-20变成了一个非常大<br />的正整数，所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的<br />嵌入式系统来说是丰常重要的。如果你答错了这个问题，你也就到了得不到这份工作的边<br />缘。<br /><br />13. 评价下面的代码片断：<br />unsigned int zero = 0; <br />unsigned int compzero = 0xFFFF; <br />/*1's complement of zero */<br /><br />对于一个int型不是16位的处理器为说，上面的代码是不正确的。应编写如下：<br />unsigned int compzero = ~0;<br /><br />这一问题真正能揭露出应试者是否懂得处理器字长的重要性。在我的经验里，好的嵌入式<br />程序员非常准确地明白硬件的细节和它的局限，然而PC机程序往往把硬件作为一个无法避<br />免的烦恼。 <br />到了这个阶段，应试者或者完全垂头丧气了或者信心满满志在必得。如果显然应试者不是<br />很好，那么这个测试就在这里结束了。但如果显然应试者做得不错，那么我就扔出下面的<br />追加问题，这些问题是比较难的，我想仅仅非常优秀的应试者能做得不错。提出这些问题<br />，我希望更多看到应试者应付问题的方法，而不是答案。不管如何，你就当是这个</font>
		<nobr>
				<a class="iAs" oncontextmenu="return false;" onmousemove="kwM(6);" onmouseover="kwE(event,6);" style="CURSOR: hand; COLOR: #0000ff; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" onclick="window.open('http://211.100.30.165/search/?key=娱乐','_blank');" onmouseout="kwL(event);" target="_blank">娱乐</a>
		</nobr>
		<font color="#003366">吧<br />…<br /><br />动态内存分配（Dynamic memory allocation）<br /><br />14. 尽管不像非嵌入式计算机那么常见，嵌入式系统还是有从堆（heap）中动态分配内存<br />的过程的。那么嵌入式系统中，动态分配内存可能发生的问题是什么？<br />这里，我期望应试者能提到内存碎片，碎片收集的问题，变量的持行时间等等。这个主题<br />已经在ESP杂志中被广泛地讨论过了（主要是 P.J. Plauger, 他的解释远远超过我这里能<br />提到的任何解释），所有回过头看一下这些杂志吧！让应试者进入一种虚假的安全感觉后<br />，我拿出这么一个小节目：下面的代码片段的输出是什么，为什么？<br /><br />char *ptr; <br />if ((ptr = (char *)malloc(0)) == NULL) <br />puts("Got a null pointer"); <br />else <br />puts("Got a valid pointer"); <br /><br />这是一个有趣的问题。最近在我的一个同事不经意把0值传给了函数malloc，得到了一个合<br />法的指针之后，我才想到这个问题。这就是上面的代码，该代码的输出是“Got a valid <br />pointer”。我用这个来开始讨论这样的一问题，看看被面试者是否想到库例程这样做是正<br />确。得到正确的答案固然重要，但解决问题的方法和你做决定的基本原理更重要些。<br /><br />Typedef <br /><br />15. Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理<br />器做类似的事。例如，思考一下下面的例子： <br />#define dPS struct s * <br />typedef struct s * tPS; <br /><br />以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢？<br />（如果有的话）为什么？ <br />这是一个非常微妙的问题，任何人答对这个问题（正当的原因）是应当被恭喜的。答案是<br />：typedef更好。思考下面的例子： <br />dPS p1,p2; <br />tPS p3,p4;<br /><br />第一个扩展为 <br />struct s * p1, p2;<br /><br />上面的代码定义p1为一个指向结构的指，p2为一个实际的结构，这也许不是你想要的。第<br />二个例子正确地定义了p3 和p4 两个指针。<br /><br />晦涩的语法<br /><br />16. C语言同意一些令人震惊的结构,下面的结构是合法的吗，如果是它做些什么？ <br />int a = 5, b = 7, c; <br />c = a+++b;<br /><br /><br />这个问题将做为这个测验的一个愉快的结尾。不管你相不相信，上面的例子是完全合乎语<br />法的。问题是编译器如何处理它？水平不高的编译作者实际上会争论这个问题，根据最处<br />理原则，编译器应当能处理尽可能所有合法的用法。因此，上面的代码被处理成： <br />c = a++ + b; <br />因此, 这段代码持行后a = 6, b = 7, c = 12。 <br />如果你知道答案，或猜出正确答案，做得好。如果你不知道答案，我也不把这个当作问题<br />。我发现这个问题的最大好处是:这是一个关于代码编写风格，代码的可读性，代码的可修<br />改性的好的话题</font>
		<br />  
<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1376560</p><img src ="http://www.cppblog.com/shaovie/aggbug/15710.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaovie/" target="_blank">崔少伟</a> 2006-11-28 08:39 <a href="http://www.cppblog.com/shaovie/articles/15710.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ 库综述</title><link>http://www.cppblog.com/shaovie/articles/14615.html</link><dc:creator>崔少伟</dc:creator><author>崔少伟</author><pubDate>Fri, 03 Nov 2006 05:25:00 GMT</pubDate><guid>http://www.cppblog.com/shaovie/articles/14615.html</guid><wfw:comment>http://www.cppblog.com/shaovie/comments/14615.html</wfw:comment><comments>http://www.cppblog.com/shaovie/articles/14615.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaovie/comments/commentRss/14615.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaovie/services/trackbacks/14615.html</trackback:ping><description><![CDATA[转自:http://joycenter.bokee.com/700023.html<br /><p>在C++中，库的地位是非常高的。C++之父 Bjarne Stroustrup先生多次表示了设计库来扩充功能要好过设计更多的语法的言论。现实中，C++的库门类繁多，解决的问题也是极其广泛，库从轻量级到重量级的都有。不少都是让人眼界大开，亦或是望而生叹的思维杰作。由于库的数量非常庞大，而且限于笔者水平，其中很多并不了解。所以文中所提的一些库都是比较著名的大型库。<br /></p><p>在C++中，库的地位是非常高的。C++之父 Bjarne Stroustrup先生多次表示了设计库来扩充功能要好过设计更多的语法的言论。现实中，C++的库门类繁多，解决的问题也是极其广泛，库从轻量级到重量级的都有。不少都是让人眼界大开，亦或是望而生叹的思维杰作。由于库的数量非常庞大，而且限于笔者水平，其中很多并不了解。所以文中所提的一些库都是比较著名的大型库。</p><p>标准库</p><p>标准库中提供了C++程序的基本设施。虽然C++标准库随着C++标准折腾了许多年，直到标准的出台才正式定型，但是在标准库的实现上却很令人欣慰得看到多种实现，并且已被实践证明为有工业级别强度的佳作。</p><p>1、   Dinkumware C++ Library</p><p>参考站点：<a href="http://www.dinkumware.com/%27%3Ehttp://www.dinkumware.com/">http://www.dinkumware.com/'&gt;http://www.dinkumware.com/</a></p><p>P.J. Plauger编写的高品质的标准库。P.J. Plauger博士是Dr. Dobb's程序设计杰出奖的获得者。其编写的库长期被Microsoft采用，并且最近Borland也取得了其OEM的license，在其C/C+ +的产品中采用Dinkumware的库。</p><p>2、   RogueWave Standard C++ Library</p><p>参考站点：<a href="http://www.roguewave.com/%27%3Ehttp://www.roguewave.com/%27%3Ehttp://www.roguewave.com/%27%3Ehttp://www.roguewave.com/">http://www.roguewave.com/'&gt;http://www.roguewave.com/'&gt;http://www.roguewave.com/'&gt;http://www.roguewave.com/</a></p><p>这个库在Borland C++ Builder的早期版本中曾经被采用，后来被其他的库给替换了。笔者不推荐使用。</p><p>3、SGI STL</p><p>参考站点：<a href="http://www.roguewave.com/%27%3Ehttp://www.roguewave.com/%27%3Ehttp://www.roguewave.com/%27%3Ehttp://www.roguewave.com/">http://www.roguewave.com/'&gt;http://www.roguewave.com/'&gt;http://www.roguewave.com/'&gt;http://www.roguewave.com/</a></p><p>SGI公司的C++标准模版库。</p><p>4、STLport</p><p>参考站点：<a href="http://www.stlport.org/%27%3Ehttp://www.stlport.org/">http://www.stlport.org/'&gt;http://www.stlport.org/</a></p><p>SGI STL库的跨平台可移植版本。</p><p> </p><p>准标准库——Boost</p><p>Boost 库是一个经过千锤百炼、可移植、提供源代码的C++库，作为标准库的后备，是C++标准化进程的发动机之一。 Boost库由C++标准委员会库工作组成员发起，在C++社区中影响甚大，其成员已近2000人。 Boost库为我们带来了最新、最酷、最实用的技术，是不折不扣的"准"标准库。</p><p>Boost中比较有名气的有这么几个库：</p><p>Regex<br />正则表达式库</p><p>Spirit<br />LL parser framework，用C++代码直接表达EBNF</p><p>Graph<br />图组件和算法</p><p>Lambda<br />在调用的地方定义短小匿名的函数对象，很实用的functional功能</p><p>concept check<br />检查泛型编程中的concept</p><p>Mpl<br />用模板实现的元编程框架</p><p>Thread<br />可移植的C++多线程库</p><p>Python<br />把C++类和函数映射到Python之中</p><p>Pool<br />内存池管理</p><p>smart_ptr<br />5个智能指针，学习智能指针必读，一份不错的参考是来自CUJ的文章：</p><p>Smart Pointers in Boost,哦，这篇文章可以查到，CUJ是提供在线浏览的。中文版见笔者在《Dr. Dobb's Journal软件研发杂志》第7辑上的译文。</p><p><br />Boost 总体来说是实用价值很高，质量很高的库。并且由于其对跨平台的强调，对标准C++的强调，是编写平台无关，现代C++的开发者必备的工具。但是Boost 中也有很多是实验性质的东西，在实际的开发中实用需要谨慎。并且很多Boost中的库功能堪称对语言功能的扩展，其构造用尽精巧的手法，不要贸然的花费时间研读。Boost另外一面，比如Graph这样的库则是具有工业强度，结构良好，非常值得研读的精品代码，并且也可以放心的在产品代码中多多利用。</p><p>参考站点：<a href="http://www.boost.org%27%3ehttp//www.boost.org">http://www.boost.org'&gt;http://www.boost.org</a>（国内镜像：<a href="http://www.c%27%3ehttp//www.c%27%3Ehttp://www.c%27%3Ehttp://www.c-view.org/tech/lib/boost/index.htm">http://www.c'&gt;http://www.c'&gt;http://www.c'&gt;http://www.c-view.org/tech/lib/boost/index.htm</a>）</p><p>GUI</p><p>在众多C++的库中，GUI部分的库算是比较繁荣，也比较引人注目的。在实际开发中，GUI库的选择也是非常重要的一件事情，下面我们综述一下可选择的GUI库，各自的特点以及相关工具的支持。</p><p>1、   MFC</p><p>大名鼎鼎的微软基础类库（Microsoft Foundation Class）。大凡学过VC++的人都应该知道这个库。虽然从技术角度讲，MFC是不大漂亮的，但是它构建于Windows API 之上，能够使程序员的工作更容易,编程效率高，减少了大量在建立 Windows 程序时必须编写的代码，同时它还提供了所有一般 C++ 编程的优点，例如继承和封装。MFC 编写的程序在各个版本的Windows操作系统上是可移植的，例如，在 Windows 3.1下编写的代码可以很容易地移植到 Windows NT 或 Windows 95 上。但是在最近发展以及官方支持上日渐势微。</p><p> </p><p>2、   QT</p><p>参考网站：<a href="http://www.trolltech.com/%27%3Ehttp://www.trolltech.com/">http://www.trolltech.com/'&gt;http://www.trolltech.com/</a></p><p>Qt 是Trolltech公司的一个多平台的C++图形用户界面应用程序框架。它提供给应用程序开发者建立艺术级的图形用户界面所需的所用功能。Qt是完全面向对象的很容易扩展，并且允许真正地组件编程。自从1996年早些时候，Qt进入商业领域，它已经成为全世界范围内数千种成功的应用程序的基础。Qt也是流行的Linux桌面环境KDE 的基础，同时它还支持Windows、Macintosh、Unix/X11等多种平台。</p><p> </p><p>3、WxWindows</p><p>参考网站：<a href="http://www.wxwindows.org/%27%3Ehttp://www.wxwindows.org/">http://www.wxwindows.org/'&gt;http://www.wxwindows.org/</a></p><p>跨平台的GUI库。因为其类层次极像MFC，所以有文章介绍从MFC到WxWindows的代码移植以实现跨平台的功能。通过多年的开发也是一个日趋完善的 GUI库，支持同样不弱于前面两个库。并且是完全开放源代码的。新近的C++ Builder X的GUI设计器就是基于这个库的。</p><p>4、Fox</p><p>开放源代码的GUI库。作者从自己亲身的开发经验中得出了一个理想的GUI库应该是什么样子的感受出发，从而开始了对这个库的开发。有兴趣的可以尝试一下。</p><p>参考网站：<a href="http://www.fox%27%3ehttp//www.fox-toolkit.org/">http://www.fox'&gt;http://www.fox-toolkit.org/</a></p><p>5、   WTL</p><p>基于ATL的一个库。因为使用了大量ATL的轻量级手法，模板等技术，在代码尺寸，以及速度优化方面做得非常到位。主要面向的使用群体是开发COM轻量级供网络下载的可视化控件的开发者。</p><p>6、   GTK</p><p>参考网站：<a href="http://gtkmm.sourceforge.net/">http://gtkmm.sourceforge.net/</a></p><p>GTK是一个大名鼎鼎的C的开源GUI库。在Linux世界中有Gnome这样的杀手应用。而GTK就是这个库的C++封装版本。</p><p>库</p><p><br />网络通信</p><p>ACE</p><p>参考网站：<a href="http://www.c%27%3ehttp//www.c%27%3Ehttp://www.c%27%3Ehttp://www.cs.wustl.edu/~schmidt/ACE.html">http://www.c'&gt;http://www.c'&gt;http://www.c'&gt;http://www.cs.wustl.edu/~schmidt/ACE.html</a></p><p>C+ +库的代表，超重量级的网络通信开发框架。ACE自适配通信环境（Adaptive Communication Environment）是可以自由使用、开放源代码的面向对象框架，在其中实现了许多用于并发通信软件的核心模式。ACE提供了一组丰富的可复用C++ 包装外观（Wrapper Facade）和框架组件，可跨越多种平台完成通用的通信软件任务，其中包括：事件多路分离和事件处理器分派、信号处理、服务初始化、进程间通信、共享内存管理、消息路由、分布式服务动态（重）配置、并发执行和同步，等等。</p><p>StreamModule</p><p>参考网站：<a href="http://www.omnifarious.org/StrMod/%27%3Ehttp://www.omnifarious.org/StrMod/">http://www.omnifarious.org/StrMod/'&gt;http://www.omnifarious.org/StrMod/</a></p><p>设计用于简化编写分布式程序的库。尝试着使得编写处理异步行为的程序更容易，而不是用同步的外壳包起异步的本质。</p><p>SimpleSocket</p><p>参考网站：<a href="http://home.hetnet.nl/~lcbokkers/simsock.htm">http://home.hetnet.nl/~lcbokkers/simsock.htm</a></p><p>这个类库让编写基于socket的客户/服务器程序更加容易。</p><p>A Stream Socket API for C++</p><p>参考网站：<a href="http://www.pcs.cnu.edu/%27%3Ehttp://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.html">http://www.pcs.cnu.edu/'&gt;http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.html</a></p><p>又一个对Socket的封装库。</p><p>XML</p><p>Xerces</p><p>参考网站：<a href="http://xml.apache.org/xerces-c/">http://xml.apache.org/xerces-c/</a></p><p>Xerces-C++ 是一个非常健壮的XML解析器，它提供了验证，以及SAX和DOM API。XML验证在文档类型定义(Document Type Definition，DTD)方面有很好的支持，并且在2001年12月增加了支持W3C XML Schema 的基本完整的开放标准。</p><p>XMLBooster</p><p>参考网站：<a href="http://www.xmlbooster.com/%27%3Ehttp://www.xmlbooster.com/">http://www.xmlbooster.com/'&gt;http://www.xmlbooster.com/</a></p><p>这个库通过产生特制的parser的办法极大的提高了XML解析的速度，并且能够产生相应的GUI程序来修改这个parser。在DOM和SAX两大主流XML解析办法之外提供了另外一个可行的解决方案。</p><p>Pull Parser</p><p>         参考网站：<a href="http://www.extreme.indiana.edu/xgws/xsoap/xpp/%27%3Ehttp://www.extreme.indiana.edu/xgws/xsoap/xpp/">http://www.extreme.indiana.edu/xgws/xsoap/xpp/'&gt;http://www.extreme.indiana.edu/xgws/xsoap/xpp/</a></p><p>         这个库采用pull方法的parser。在每个SAX的parser底层都有一个pull的parser，这个xpp把这层暴露出来直接给大家使用。在要充分考虑速度的时候值得尝试。</p><p>Xalan</p><p>         参考网站：<a href="http://xml.apache.org/xalan-c/">http://xml.apache.org/xalan-c/</a></p><p>         Xalan是一个用于把XML文档转换为HTML，纯文本或者其他XML类型文档的XSLT处理器。</p><p>CMarkup</p><p>         参考网站：<a href="http://www.firstobject.com/xml.htm%27%3Ehttp://www.firstobject.com/xml.htm">http://www.firstobject.com/xml.htm'&gt;http://www.firstobject.com/xml.htm</a></p><p>         这是一种使用EDOM的XML解析器。在很多思路上面非常灵活实用。值得大家在DOM和SAX之外寻求一点灵感。</p><p>libxml++</p><p><a href="http://libxmlplusplus.sourceforge.net/">http://libxmlplusplus.sourceforge.net/</a></p><p>libxml++是对著名的libxml XML解析器的C++封装版本</p><p> </p><p>科学计算</p><p>Blitz++</p><p>参考网站：<a href="http://www.oonumerics.org/blitz/%27%3Ehttp://www.oonumerics.org/blitz/">http://www.oonumerics.org/blitz/'&gt;http://www.oonumerics.org/blitz/</a></p><p>Blitz++ 是一个高效率的数值计算函数库，它的设计目的是希望建立一套既具像C++ 一样方便，同时又比Fortran速度更快的数值计算环境。通常，用C++所写出的数值程序，比 Fortran慢20%左右，因此Blitz++正是要改掉这个缺点。方法是利用C++的template技术，程序执行甚至可以比Fortran更快。 Blitz++目前仍在发展中，对于常见的SVD，FFTs，QMRES等常见的线性代数方法并不提供，不过使用者可以很容易地利用Blitz++所提供的函数来构建。</p><p>POOMA</p><p>参考网站：<a href="http://www.c%27%3ehttp//www.c%27%3Ehttp://www.c%27%3Ehttp://www.codesourcery.com/pooma/pooma">http://www.c'&gt;http://www.c'&gt;http://www.c'&gt;http://www.codesourcery.com/pooma/pooma</a></p><p>POOMA是一个免费的高性能的C++库，用于处理并行式科学计算。POOMA的面向对象设计方便了快速的程序开发，对并行机器进行了优化以达到最高的效率，方便在工业和研究环境中使用。</p><p>MTL</p><p>参考网站：<a href="http://www.osl.iu.edu/research/mtl/%27%3Ehttp://www.osl.iu.edu/research/mtl/">http://www.osl.iu.edu/research/mtl/'&gt;http://www.osl.iu.edu/research/mtl/</a></p><p>Matrix Template Library(MTL)是一个高性能的泛型组件库，提供了各种格式矩阵的大量线性代数方面的功能。在某些应用使用高性能编译器的情况下，比如Intel的编译器，从产生的汇编代码可以看出其与手写几乎没有两样的效能。</p><p>CGAL</p><p>参考网站：<a href="http://www.cgal.org/">www.cgal.org</a></p><p>Computational Geometry Algorithms Library的目的是把在计算几何方面的大部分重要的解决方案和方法以C++库的形式提供给工业和学术界的用户。</p><p> </p><p>游戏开发</p><p>Audio/Video 3D C++ Programming Library</p><p>参考网站：<a href="http://www.galacticasoftware.com/products/av/%27%3Ehttp://www.galacticasoftware.com/products/av/">http://www.galacticasoftware.com/products/av/'&gt;http://www.galacticasoftware.com/products/av/</a></p><p>AV3D是一个跨平台，高性能的C++库。主要的特性是提供3D图形，声效支持（SB,以及S3M），控制接口（键盘，鼠标和遥感），XMS。</p><p>KlayGE</p><p>参考网站：<a href="http://home.g365.net/enginedev/">http://home.g365.net/enginedev/</a></p><p>国内游戏开发高手自己用C++开发的游戏引擎。KlayGE是一个开放源代码、跨平台的游戏引擎，并使用Python作脚本语言。KlayGE在LGPL协议下发行。感谢龚敏敏先生为中国游戏开发事业所做出的贡献。</p><p>OGRE</p><p>参考网站：<a href="http://www.ogre3d.org%27%3ehttp//www.ogre3d.org">http://www.ogre3d.org'&gt;http://www.ogre3d.org</a></p><p>OGRE （面向对象的图形渲染引擎）是用C++开发的，使用灵活的面向对象3D引擎。它的目的是让开发者能更方便和直接地开发基于3D硬件设备的应用程序或游戏。引擎中的类库对更底层的系统库（如：Direct3D和OpenGL）的全部使用细节进行了抽象，并提供了基于现实世界对象的接口和其它类。</p><p> </p><p>线程</p><p>C++ Threads</p><p>参考网站：<a href="http://threads.sourceforge.net/">http://threads.sourceforge.net/</a></p><p>这个库的目标是给程序员提供易于使用的类，这些类被继承以提供在Linux环境中很难看到的大量的线程方面的功能。</p><p>ZThreads</p><p>参考网站：<a href="http://zthread.sourceforge.net/">http://zthread.sourceforge.net/</a></p><p>一个先进的面向对象，跨平台的C++线程和同步库。</p><p> </p><p>序列化</p><p>s11n</p><p>参考网站：<a href="http://s11n.net/">http://s11n.net/</a></p><p>一个基于STL的C++库，用于序列化POD，STL容器以及用户定义的类型。</p><p>Simple XML Persistence Library</p><p>参考网站：<a href="http://sxp.sourceforge.net/">http://sxp.sourceforge.net/</a></p><p>这是一个把对象序列化为XML的轻量级的C++库。</p><p> </p><p>字符串</p><p>C++ Str Library</p><p>参考网站：<a href="http://www.utilitycode.com/str/%27%3Ehttp://www.utilitycode.com/str/">http://www.utilitycode.com/str/'&gt;http://www.utilitycode.com/str/</a></p><p>操作字符串和字符的库，支持Windows和支持gcc的多种平台。提供高度优化的代码，并且支持多线程环境和Unicode，同时还有正则表达式的支持。</p><p>Common Text Transformation Library</p><p>参考网站：<a href="http://cttl.sourceforge.net/">http://cttl.sourceforge.net/</a></p><p>这是一个解析和修改STL字符串的库。CTTL substring类可以用来比较，插入，替换以及用EBNF的语法进行解析。</p><p>GRETA</p><p>参考网站：<a href="http://research.microsoft.com/projects/greta/">http://research.microsoft.com/projects/greta/</a></p><p>这是由微软研究院的研究人员开发的处理正则表达式的库。在小型匹配的情况下有非常优秀的表现。</p><p>综合</p><p>P::Classes</p><p>参考网站：<a href="http://pclasses.com/">http://pclasses.com/</a></p><p>一个高度可移植的C++应用程序框架。当前关注类型和线程安全的signal/slot机制，i/o系统包括基于插件的网络协议透明的i/o架构，基于插件的应用程序消息日志框架，访问sql数据库的类等等。</p><p>ACDK - Artefaktur Component Development Kit</p><p>参考网站：<a href="http://acdk.sourceforge.net/">http://acdk.sourceforge.net/</a></p><p>这是一个平台无关的C++组件框架，类似于Java或者.NET中的框架（反射机制，线程，Unicode，废料收集，I/O，网络，实用工具，XML，等等），以及对Java, Perl, Python, TCL, Lisp, COM 和 CORBA的集成。</p><p>dlib C++ library</p><p>参考网站：<a href="http://www.c%27%3ehttp//www.c%27%3Ehttp://www.c%27%3Ehttp://www.cis.ohio-state.edu/~kingd/dlib/">http://www.c'&gt;http://www.c'&gt;http://www.c'&gt;http://www.cis.ohio-state.edu/~kingd/dlib/</a></p><p>各种各样的类的一个综合。大整数，Socket，线程，GUI，容器类,以及浏览目录的API等等。</p><p>Chilkat C++ Libraries</p><p>参考网站：<a href="http://www.c%27%3ehttp//www.c%27%3Ehttp://www.c%27%3Ehttp://www.chilkatsoft.com/cpp_libraries.asp">http://www.c'&gt;http://www.c'&gt;http://www.c'&gt;http://www.chilkatsoft.com/cpp_libraries.asp</a></p><p>这是提供zip，e-mail，编码，S/MIME，XML等方面的库。</p><p>C++ Portable Types Library (PTypes)</p><p>参考网站：<a href="http://www.melikyan.com/ptypes/%27%3Ehttp://www.melikyan.com/ptypes/">http://www.melikyan.com/ptypes/'&gt;http://www.melikyan.com/ptypes/</a></p><p>这是STL的比较简单的替代品，以及可移植的多线程和网络库。</p><p>LFC</p><p>参考网站：<a href="http://lfc.sourceforge.net/">http://lfc.sourceforge.net/</a></p><p>哦，这又是一个尝试提供一切的C++库</p><p> </p><p>其他库</p><p>Loki</p><p>参考网站：<a href="http://www.moderncppdesign.com/%27%3Ehttp://www.moderncppdesign.com/%27%3Ehttp://www.moderncppdesign.com/%27%3Ehttp://www.moderncppdesign.com/">http://www.moderncppdesign.com/'&gt;http://www.moderncppdesign.com/'&gt;http://www.moderncppdesign.com/'&gt;http://www.moderncppdesign.com/</a></p><p>哦，你可能抱怨我早该和Boost一起介绍它，一个实验性质的库。作者在loki中把C++模板的功能发挥到了极致。并且尝试把类似设计模式这样思想层面的东西通过库来提供。同时还提供了智能指针这样比较实用的功能。</p><p>ATL</p><p>ATL(Active Template Library)是一组小巧、高效、灵活的类，这些类为创建可互操作的COM组件提供了基本的设施。</p><p>FC++: The Functional C++ Library</p><p>这个库提供了一些函数式语言中才有的要素。属于用库来扩充语言的一个代表作。如果想要在OOP之外寻找另一分的乐趣，可以去看看函数式程序设计的世界。大师 Peter Norvig在 "Teach Yourself Programming in Ten Years"一文中就将函数式语言列为至少应当学习的6类编程语言之一。</p><p>FACT!</p><p>参考网站：<a href="http://www.kfa%27%3ehttp//www.kfa-juelich.de/zam/FACT/start/index.html">http://www.kfa'&gt;http://www.kfa-juelich.de/zam/FACT/start/index.html</a></p><p>         另外一个实现函数式语言特性的库</p><p>Crypto++</p><p>提供处理密码，消息验证，单向hash，公匙加密系统等功能的免费库。</p><p>还有很多非常激动人心或者是极其实用的C++库，限于我们的水平以及文章的篇幅不能包括进来。在对于这些已经包含近来的库的介绍中，由于并不是每一个我们都使用过，所以难免有偏颇之处，请读者见谅。</p><p> </p><p>DObjectC++, <br />java库的C＋＋版，可灵活扩充。</p><p><br />资源网站</p><p>正如我们可以通过计算机历史上的重要人物了解计算机史的发展，C++相关人物的网站也可以使我们得到最有价值的参考与借鉴，下面的人物我们认为没有介绍的必要，只因下面的人物在C++领域的地位众所周知，我们只将相关的资源进行罗列以供读者学习，他们有的工作于贝尔实验室，有的工作于知名编译器厂商，有的在不断推进语言的标准化，有的为读者撰写了多部千古奇作......</p><p>Bjarne Stroustrup  <a href="http://www.research.att.com/%27%3Ehttp://www.research.att.com/~bs/">http://www.research.att.com/'&gt;http://www.research.att.com/~bs/</a></p><p>Stanley B. Lippman</p><p><a href="http://blogs.msdn.com/slippman/">http://blogs.msdn.com/slippman/</a>(中文版<a href="http://www.zengyihome.net%27%3ehttp//www.zengyihome.net/slippman/index.htm%27%3Ehttp://www.zengyihome.net%27%3Ehttp://www.zengyihome.net/slippman/index.htm">http://www.zengyihome.net'&gt;http://www.zengyihome.net/slippman/index.htm'&gt;http://www.zengyihome.net'&gt;http://www.zengyihome.net/slippman/index.htm</a>)</p><p>Scott Meyers  <a href="http://www.aristeia.com/%27%3Ehttp://www.aristeia.com/">http://www.aristeia.com/'&gt;http://www.aristeia.com/</a></p><p>David Musser  <a href="http://www.c%27%3ehttp//www.c%27%3Ehttp://www.c%27%3Ehttp://www.cs.rpi.edu/~musser/">http://www.c'&gt;http://www.c'&gt;http://www.c'&gt;http://www.cs.rpi.edu/~musser/</a></p><p>Bruce Eckel  <a href="http://www.bruceeckel.com%27%3ehttp//www.bruceeckel.com">http://www.bruceeckel.com'&gt;http://www.bruceeckel.com</a></p><p>Nicolai M. Josuttis  <a href="http://www.josuttis.com/%27%3Ehttp://www.josuttis.com/">http://www.josuttis.com/'&gt;http://www.josuttis.com/</a></p><p>Herb Sutter  <a href="http://www.gotw.ca/%27%3Ehttp://www.gotw.ca/">http://www.gotw.ca/'&gt;http://www.gotw.ca/</a></p><img src ="http://www.cppblog.com/shaovie/aggbug/14615.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaovie/" target="_blank">崔少伟</a> 2006-11-03 13:25 <a href="http://www.cppblog.com/shaovie/articles/14615.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>静态成员的初始化序列</title><link>http://www.cppblog.com/shaovie/articles/14423.html</link><dc:creator>崔少伟</dc:creator><author>崔少伟</author><pubDate>Tue, 31 Oct 2006 06:32:00 GMT</pubDate><guid>http://www.cppblog.com/shaovie/articles/14423.html</guid><wfw:comment>http://www.cppblog.com/shaovie/comments/14423.html</wfw:comment><comments>http://www.cppblog.com/shaovie/articles/14423.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaovie/comments/commentRss/14423.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaovie/services/trackbacks/14423.html</trackback:ping><description><![CDATA[
		<p>#include &lt;stdio.h&gt;</p>
		<p>class Base<br />{<br />        public:<br />        static void set (bool islive)<br />        {<br />                live = islive;<br />        }<br />        static bool get (){return live;}<br />        private:<br />        static bool live;<br />};<br />bool Base::live = true;<br />int main ()<br />{<br />        Base::set (false);<br />        puts ( Base::get () ? "live" : "no live");<br />        Base * tp = new Base ();<br />        puts ( tp-&gt;get () ? "live" : "no live");<br />}<br />结果:<br />[ace@SSWork Terminal]$ ./a.out<br />no live<br />no live<br />//静态成员在程序一开始的时候进行初始化.<br /></p>
<img src ="http://www.cppblog.com/shaovie/aggbug/14423.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaovie/" target="_blank">崔少伟</a> 2006-10-31 14:32 <a href="http://www.cppblog.com/shaovie/articles/14423.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>尽量使用C++风格的类型转换</title><link>http://www.cppblog.com/shaovie/articles/14281.html</link><dc:creator>崔少伟</dc:creator><author>崔少伟</author><pubDate>Fri, 27 Oct 2006 08:48:00 GMT</pubDate><guid>http://www.cppblog.com/shaovie/articles/14281.html</guid><wfw:comment>http://www.cppblog.com/shaovie/comments/14281.html</wfw:comment><comments>http://www.cppblog.com/shaovie/articles/14281.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaovie/comments/commentRss/14281.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaovie/services/trackbacks/14281.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.3pt; LINE-HEIGHT: 150%">
				<font face="Times New Roman">
						<font size="4">
								<span lang="EN-US" style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">转:<br />C</span>
								<span style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">风格的类型转换：一来它们过于粗鲁，能允许你在任何类型之间进行转换。不过如果要进行更精确的类型转换，这会是一个优点。二来<span lang="EN-US">C</span>风格的类型转换在程序语句中难以识别。<span lang="EN-US"><?xml:namespace prefix = o /?><o:p></o:p></span></span>
						</font>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.3pt; LINE-HEIGHT: 150%">
				<font face="Times New Roman">
						<font size="4">
								<span lang="EN-US" style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">C++</span>
								<span style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">通过引进四个新的类型转换操作符克服了<span lang="EN-US">C</span>风格类型转换的缺点，<span lang="EN-US"> static_cast, const_cast, dynamic_cast, </span>和<span lang="EN-US">reinterpret_cast</span>。<span lang="EN-US">(type) expression </span>＝＝》<span lang="EN-US">static_cast&lt;type&gt;(expression)<o:p></o:p></span></span>
						</font>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.3pt; LINE-HEIGHT: 150%">
				<font face="Times New Roman">
						<font size="4">
								<span lang="EN-US" style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">static_cast</span>
								<span style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">在功能上基本上与<span lang="EN-US">C</span>风格的类型转换一样强大，含义也一样。它也有功能上限制。例如，你不能用<span lang="EN-US">static_cast</span>象用<span lang="EN-US">C</span>风格的类型转换一样把<span lang="EN-US">struct</span>转换成<span lang="EN-US">int</span>类型或者把<span lang="EN-US">double</span>类型转换成指针类型，<span lang="EN-US"><o:p></o:p></span></span>
						</font>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.3pt; LINE-HEIGHT: 150%">
				<font face="Times New Roman">
						<font size="4">
								<span lang="EN-US" style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">static_cast</span>
								<span style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">不能从表达式中去除<span lang="EN-US">const</span>属性，因为另一个新的类型转换操作符<span lang="EN-US">const_cast</span>有这样的功能。<span lang="EN-US"><o:p></o:p></span></span>
						</font>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.3pt; LINE-HEIGHT: 150%">
				<font face="Times New Roman">
						<font size="4">
								<span lang="EN-US" style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">const_cast</span>
								<span style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">用于类型转换掉表达式的<span lang="EN-US">const</span>或<span lang="EN-US">volatileness</span>属性。到目前为止，<span lang="EN-US">const_cast</span>最普通的用途就是转换掉对象的<span lang="EN-US">const</span>属性。<span lang="EN-US"><o:p></o:p></span></span>
						</font>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.3pt; LINE-HEIGHT: 150%">
				<font face="Times New Roman">
						<font size="4">
								<span lang="EN-US" style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">dynamic_cast</span>
								<span style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">，它被用于安全地沿着类的继承关系向下进行类型转换。这就是说，你能用<span lang="EN-US">dynamic_cast</span>把指向基类的指针或引用转换成指向其派生类或其兄弟类的指针或引用，而且你能知道转换是否成功。失败的转换将返回空指针（<font size="4">当对指针进行类型转换时）或者抛出异常（当对引用进行类型转换时）。<span lang="EN-US">dynamic_casts</span>在帮助你浏览继承层次上是有限制的。它不能被用于缺乏虚函数的类型上（参见条款<span lang="EN-US">M24</span>），也不能用它来转换掉<span lang="EN-US">constness</span>。<span lang="EN-US"><o:p></o:p></span></font></span>
						</font>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.3pt; LINE-HEIGHT: 150%">
				<span style="FONT-SIZE: 10.5pt; LINE-HEIGHT: 150%; FONT-FAMILY: 宋体">
						<font face="Times New Roman" size="4">如你想在没有继承关系的类型中进行转换，你可能想到<span lang="EN-US">static_cast</span>。如果是为了去除<span lang="EN-US">const</span>，你总得用<span lang="EN-US">const_cast</span>。<br />   </font>
						<font face="Times New Roman">
								<font size="4">dynamic_cast依赖于RTTI信息，其次，在转换时，dynamic_cast会检查转换的source对象是否真的可以转换成target类型，这种检查不是语法上的，而是真实情况的检查。<br />先看RTTI相关部分，通常，许多编译器都是通过vtable找到对象的RTTI信息的，这也就意味着，如果基类没有虚方法，也就无法判断一个基类指针变量所指对象的真实类型, 这时候，dynamic_cast只能用来做安全的转换,例如从派生类指针转换成基类指针.而这种转换其实并不需要dynamic_cast参与.<br />也就是说,dynamic_cast是根据RTTI记载的信息来判断类型转换是否合法的.<br /><br />下面看一个例子:<br />struct B1{<br />    virtual ~B1(){}<br />};<br />struct B2{<br />    virtual ~B2(){}<br />};<br />struct D1 : B1, B2{};<br />int main()<br />{<br />    D1 d;<br />    B1* pb1 = &amp;d;<br />    B2* pb2 = dynamic_cast&lt;B2*&gt;(pb1);//L1<br />    B2* pb22 = static_cast&lt;B2*&gt;(pb1);  //L2<br />    return 0;<br />}<br />上述定义中可以看到,B1和B2是不相关的类,从L1可以看到,dynamic_cast允许这种转换:只要B1存在多态方法.<br />L2将编译失败,static_cast并不允许两个完全不相干的类互相转换.<br /><br />dynamic_cast的这种特性，在提取一个对象的某个接口的时候，非常有用，它很类似于实现了COM的QueryInterface的功能。<br />dynamic_cast 主要用于执行“安全的向下转型（safe downcasting）”，也就是说，要确定一个对象是否是一个继承体系中的一个特定类型。它是唯一不能用旧风格语法执行的强制转型。也是唯一可能有重大运行时代价的强制转型。<br /><span lang="EN-US"><o:p></o:p></span></font>
						</font>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.3pt; LINE-HEIGHT: 150%">
				<font size="4">
						<span lang="EN-US">reinterpret_cast</span>
						<font face="Times New Roman">
								<span style="FONT-FAMILY: 宋体">。使用这个操作符的类型转换，其的转换结果几乎都是执行期定义（</span>
								<span lang="EN-US">implementation-defined</span>
								<span style="FONT-FAMILY: 宋体">）。因此，使用</span>
								<span lang="EN-US">reinterpret_casts</span>
								<span style="FONT-FAMILY: 宋体">的代码很难移植。</span>
								<span lang="EN-US">reinterpret_casts</span>
								<span style="FONT-FAMILY: 宋体">的最普通的用途就是在函数指针类型之间进行转换。</span>
						</font>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21.3pt; LINE-HEIGHT: 150%">
				<font face="Times New Roman">
						<font size="4">
								<span style="FONT-FAMILY: 宋体">正是因为新的类型转换符缺乏美感才能使它弥补了在含义精确性和可辨认性上的缺点。使用新类型转换符的程序更容易被解析（不论是对人工还是对于工具程序），它们允许编译器检测出原来不能发现的错误。这些都是放弃</span>
								<span lang="EN-US">C</span>
								<span style="FONT-FAMILY: 宋体">风格类型转换方法的强有力的理由。还有第三个理由：也许让类型转换符不美观和键入麻烦是一件好事。</span>
						</font>
				</font>
		</p>
<img src ="http://www.cppblog.com/shaovie/aggbug/14281.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaovie/" target="_blank">崔少伟</a> 2006-10-27 16:48 <a href="http://www.cppblog.com/shaovie/articles/14281.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言中如何使用宏</title><link>http://www.cppblog.com/shaovie/articles/14038.html</link><dc:creator>崔少伟</dc:creator><author>崔少伟</author><pubDate>Mon, 23 Oct 2006 05:47:00 GMT</pubDate><guid>http://www.cppblog.com/shaovie/articles/14038.html</guid><wfw:comment>http://www.cppblog.com/shaovie/comments/14038.html</wfw:comment><comments>http://www.cppblog.com/shaovie/articles/14038.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/shaovie/comments/commentRss/14038.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaovie/services/trackbacks/14038.html</trackback:ping><description><![CDATA[
		<span class="oblog_text">转载<br />C语言中如何使用宏C（和C++）中的宏（Macro）属于编译器预处理的范畴，属于编译期概念（而非运行期概念）。下面对常遇到的宏的使用问题做了简单总结。 
<h3 id="h2_1_1">关于#和##</h3>在C语言的宏中，#的功能是将其后面的宏参数进行字符串化操作（Stringfication），简单说就是在对它所引用的<strong>宏变量</strong>通过替换后在其左右各加上一个双引号。比如下面代码中的宏： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">#define WARN_IF(EXP)    \
    do{ if (EXP)    \
            fprintf(stderr, "Warning: " #EXP "\n"); }   \
    while(0)
</pre>那么实际使用中会出现下面所示的替换过程： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">WARN_IF (divider == 0);

	<strong>被替换为</strong>

do {
    if (divider == 0)
		fprintf(stderr, "Warning" "divider == 0" "\n");
} while(0);
</pre>这样每次divider（除数）为0的时候便会在标准错误流上输出一个提示信息。 
<p>而##被称为连接符（concatenator），用来将两个Token连接为一个Token。注意这里连接的对象是Token就行，而<em>不一定</em>是宏的变量。比如你要做一个菜单项命令名和函数指针组成的结构体的数组，并且希望在函数名和菜单项命令名之间有直观的、名字上的关系。那么下面的代码就非常实用： </p><pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">struct command
{
	char * name;
	void (*function) (void);
};

#define COMMAND(NAME) { NAME, NAME ## _command }

// 然后你就用一些预先定义好的命令来方便的初始化一个command结构的数组了：

struct command commands[] = {
	COMMAND(quit),
	COMMAND(help),
	...
}
</pre>COMMAND宏在这里充当一个代码生成器的作用，这样可以在一定程度上减少代码密度，间接地也可以减少不留心所造成的错误。我们还可以n个##符号连接 n+1个Token，这个特性也是#符号所不具备的。比如： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">#define LINK_MULTIPLE(a,b,c,d) a##_##b##_##c##_##d

typedef struct _record_type LINK_MULTIPLE(name,company,position,salary);
// 这里这个语句将展开为：
// 	typedef struct _record_type name_company_position_salary;
</pre><h3 id="h2_1_2">关于...的使用</h3>...在C宏中称为Variadic Macro，也就是变参宏。比如： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">#define myprintf(templt,...) fprintf(stderr,templt,__VA_ARGS__)

	// 或者

#define myprintf(templt,args...) fprintf(stderr,templt,args)
</pre>第一个宏中由于没有对变参起名，我们用默认的宏__VA_ARGS__来替代它。第二个宏中，我们显式地命名变参为args，那么我们在宏定义中就可以用args来代指变参了。同C语言的stdcall一样，变参必须作为参数表的最有一项出现。当上面的宏中我们只能提供第一个参数templt时，C标准要求我们必须写成： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">myprintf(templt,);
</pre>的形式。这时的替换过程为： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">myprintf("Error!\n",);

	<strong>替换为：</strong>
	
fprintf(stderr,"Error!\n",);
</pre>这是一个语法错误，不能正常编译。这个问题一般有两个解决方法。首先，GNU CPP提供的解决方法允许上面的宏调用写成： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">myprintf(templt);
</pre>而它将会被通过替换变成： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">fprintf(stderr,"Error!\n",);
</pre>很明显，这里仍然会产生编译错误（非本例的某些情况下不会产生编译错误）。除了这种方式外，c99和GNU CPP都支持下面的宏定义方式： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">#define myprintf(templt, ...) fprintf(stderr,templt, ##__VAR_ARGS__)
</pre>这时，##这个连接符号充当的作用就是当__VAR_ARGS__为空的时候，消除前面的那个逗号。那么此时的翻译过程如下： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">myprintf(templt);

	<strong>被转化为：</strong>

fprintf(stderr,templt);
</pre>这样如果templt合法，将不会产生编译错误。 这里列出了一些宏使用中容易出错的地方，以及合适的使用方式。 
<h3 id="h2_3_1">错误的嵌套－Misnesting</h3>宏的定义不一定要有完整的、配对的括号，但是为了避免出错并且提高可读性，最好避免这样使用。 
<h3 id="h2_3_2">由操作符优先级引起的问题－Operator Precedence Problem</h3>由于宏只是简单的替换，宏的参数如果是复合结构，那么通过替换之后可能由于各个参数之间的操作符优先级高于单个参数内部各部分之间相互作用的操作符优先级，如果我们不用括号保护各个宏参数，可能会产生预想不到的情形。比如： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">#define ceil_div(x, y) (x + y - 1) / y
</pre>那么 <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">a = ceil_div( b &amp; c, sizeof(int) );
</pre>将被转化为： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">a = ( b &amp; c  + sizeof(int) - 1) / sizeof(int);
	// 由于+/-的优先级高于&amp;的优先级，那么上面式子等同于：
a = ( b &amp; (c + sizeof(int) - 1)) / sizeof(int);
</pre>这显然不是调用者的初衷。为了避免这种情况发生，应当多写几个括号： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">#define ceil_div(x, y) (((x) + (y) - 1) / (y))
</pre><h3 id="h2_3_3">消除多余的分号－Semicolon Swallowing</h3>通常情况下，为了使函数模样的宏在表面上看起来像一个通常的C语言调用一样，通常情况下我们在宏的后面加上一个分号，比如下面的带参宏： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">MY_MACRO(x);
</pre>但是如果是下面的情况： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">#define MY_MACRO(x) {	\
	/* line 1 */	\
	/* line 2 */	\
	/* line 3 */ }
	
//...

if (condition())
	MY_MACRO(a);
else
	{...}
</pre>这样会由于多出的那个分号产生编译错误。为了避免这种情况出现同时保持MY_MACRO(x);的这种写法，我们需要把宏定义为这种形式： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">#define MY_MACRO(x) do {
	/* line 1 */	\
	/* line 2 */	\
	/* line 3 */ } while(0)
</pre>这样只要保证总是使用分号，就不会有任何问题。 
<h3 id="h2_3_1">Duplication of Side Effects</h3>这里的Side Effect是指宏在展开的时候对其参数可能进行多次Evaluation（也就是取值），但是如果这个宏参数是一个函数，那么就有可能被调用多次从而达到不一致的结果，甚至会发生更严重的错误。比如： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">#define min(X,Y) ((X) &gt; (Y) ? (Y) : (X))

	//...
	
c = min(a,foo(b));
</pre>这时foo()函数就被调用了两次。为了解决这个潜在的问题，我们应当这样写min(X,Y)这个宏： <pre style="padding: 8pt; background: rgb(239, 239, 239) none repeat scroll 0%; font-size: small; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 2em; margin-right: 10%; font-family: 'Lucida Sans Typewriter';">#define min(X,Y) ({	\
	typeof (X) x_ = (X);	\
	typeof (Y) y_ = (Y);	\
	(x_ &lt; y_) ? x_ : y_; })
</pre>({...})的作用是将内部的几条语句中最后一条的值返回，它也允许在内部声明变量（因为它通过大括号组成了一个局部Scope）。 </span>
<img src ="http://www.cppblog.com/shaovie/aggbug/14038.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaovie/" target="_blank">崔少伟</a> 2006-10-23 13:47 <a href="http://www.cppblog.com/shaovie/articles/14038.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>"C++你知道吗?" 之 几个冷僻的关键字 (转)</title><link>http://www.cppblog.com/shaovie/articles/13993.html</link><dc:creator>崔少伟</dc:creator><author>崔少伟</author><pubDate>Sun, 22 Oct 2006 01:57:00 GMT</pubDate><guid>http://www.cppblog.com/shaovie/articles/13993.html</guid><wfw:comment>http://www.cppblog.com/shaovie/comments/13993.html</wfw:comment><comments>http://www.cppblog.com/shaovie/articles/13993.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaovie/comments/commentRss/13993.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaovie/services/trackbacks/13993.html</trackback:ping><description><![CDATA[
		<font face="宋体">
				<font size="2">from :http://www.cppblog.com/jerysun0818/archive/2006/10/21/13950.html<br />mutable关键字<br /></font>
				<br />
		</font>
		<font face="宋体">
				<font size="2">关键字mutable是C++中一个不常用的关键字,他只能用于类的非静态和非常量数据成员<br />我们知道一个对象的状态由该对象的非静态数据成员决定,所以随着数据成员的改变,<br />对像的状态也会随之发生变化!</font>
		</font>
		<p>
				<font face="宋体" size="2">如果一个类的成员函数被声明为const类型,表示该函数不会改变对象的状态,也就是<br />该函数不会修改类的非静态数据成员.但是有些时候需要在该类函数中对类的数据成员<br />进行赋值.这个时候就需要用到mutable关键字了</font>
		</p>
		<p>
				<font face="宋体" size="2">例如:<br />class Demo<br />{<br />public:<br />    Demo(){}<br />    ~Demo(){}<br />public:<br />    bool getFlag() const<br />    {<br />        m_nAccess++;<br />        return m_bFlag;<br />    }<br />private:<br />    int  m_nAccess;<br />    bool m_bFlag;<br />};</font>
		</p>
		<p>
				<font face="宋体" size="2">int main()<br />{<br />    return 0;<br />}</font>
		</p>
		<p>
				<font face="宋体" size="2">编译上面的代码会出现 error C2166: l-value specifies const object的错误<br />说明在const类型的函数中改变了类的非静态数据成员.</font>
		</p>
		<p>
				<font face="宋体" size="2">这个时候需要使用mutable来修饰一下要在const成员函数中改变的非静态数据成员<br />m_nAccess,代码如下:</font>
		</p>
		<p>
				<font face="宋体" size="2">class Demo<br />{<br />public:<br />    Demo(){}<br />    ~Demo(){}<br />public:<br />    bool getFlag() const<br />    {<br />        m_nAccess++;<br />        return m_bFlag;<br />    }<br />private:<br />    mutable int  m_nAccess;<br />    bool m_bFlag;<br />};</font>
		</p>
		<p>
				<font face="宋体" size="2">int main()<br />{<br />    return 0;<br />}</font>
		</p>
		<p>
				<font face="宋体" size="2">这样再重新编译的时候就不会出现错误了!</font>
		</p>
		<p>
				<font face="宋体" size="2">
				</font> </p>
		<p>
				<font face="宋体" size="2">
				</font> </p>
		<p>
				<font face="宋体" size="2">volatile关键字</font>
		</p>
		<p>
				<font face="宋体" size="2">volatile是c/c++中一个鲜为人知的关键字,该关键字告诉编译器不要持有变量的临时拷贝,它可以适用于基础类型<br />如：int,char,long......也适用于C的结构和C++的类。当对结构或者类对象使用volatile修饰的时候，结构或者<br />类的所有成员都会被视为volatile.</font>
		</p>
		<p>
				<font face="宋体" size="2">使用volatile并不会否定对CRITICAL_SECTION,Mutex,Event等同步对象的需要<br />例如：<br />int i;<br />i = i + 3;<br />无论如何，总是会有一小段时间，i会被放在一个寄存器中，因为算术运算只能在寄存器中进行。一般来说，volatitle<br />关键字适用于行与行之间，而不是放在行内。</font>
		</p>
		<p>
				<font face="宋体" size="2">我们先来实现一个简单的函数，来观察一下由编译器产生出来的汇编代码中的不足之处，并观察volatile关键字如何修正<br />这个不足之处。在这个函数体内存在一个busy loop(所谓busy loop也叫做busy waits,是一种高度浪费CPU时间的循环方法)</font>
		</p>
		<p>
				<font face="宋体" size="2">void getKey(char* pch)<br />{<br /> while (*pch == 0)<br />  ;<br />}</font>
		</p>
		<p>
				<font face="宋体" size="2">当你在VC开发环境中将最优化选项都关闭之后，编译这个程序，将获得以下结果(汇编代码)<br />;       while (*pch == 0)<br />$L27<br /> ; Load the address stored in pch<br /> mov eax, DWORD PTR _pch$[ebp]<br /> ; Load the character into the EAX register<br /> movsx eax, BYTE PTR [eax]<br /> ; Compare the value to zero<br /> test eax, eax<br /> ; If not zero, exit loop<br /> jne $L28<br /> ;<br /> jmp $L27<br />$L28<br />;}</font>
		</p>
		<p>
				<font face="宋体" size="2">这段没有优化的代码不断的载入适当的地址，载入地址中的内容，测试结果。效率相当的低，但是结果非常准确</font>
		</p>
		<p>
				<font face="宋体" size="2">现在我们再来看看将编译器的所有最优化选项开关都打开以后，重新编译程序，生成的汇编代码，和上面的代码<br />比较一下有什么不同<br />;{ <br /> ; Load the address stored in pch<br /> mov eax, DWORD PTR _pch$[esp-4]<br /> ; Load the character into the AL register<br /> movsx al, BYTE PTR [eax]<br />; while (*pch == 0)<br /> ; Compare the value in the AL register to zero<br /> test al, al<br /> ; If still zero, try again<br /> je SHORT $L84<br /> ;<br />;}</font>
		</p>
		<p>
				<font face="宋体" size="2">从代码的长度就可以看出来，比没有优化的情况要短的多。需要注意的是编译器把MOV指令放到了循环之外。这在<br />单线程中是一个非常好的优化，但是，在多线程应用程序中，如果另一个线程改变了变量的值，则循环永远不会<br />结束。被测试的值永远被放在寄存器中，所以该段代码在多线程的情况下，存在一个巨大的BUG。解决方法是重新<br />写一次getKey函数，并把参数pch声明为volatile,代码如下：</font>
		</p>
		<p>
				<font face="宋体" size="2">void getKey(volatile char* pch)<br />{<br /> while (*pch == 0)<br />  ;<br />}</font>
		</p>
		<p>
				<font face="宋体" size="2">这次的修改对于非最优化的版本没有任何影响，下面请看最优化后的结果：</font>
		</p>
		<p>
				<font face="宋体" size="2">;{<br /> ; Load the address stored in pch<br /> mov eax, DWORD PTR _pch$[esp-4]<br />;       while (*pch == 0)<br />$L84:<br /> ; Directly compare the value to zero<br /> cmp BYTE PTR [eax], 0<br /> ; If still zero, try again<br /> je SHORT $L84<br /> ;<br />;}</font>
		</p>
		<p>
				<font face="宋体" size="2">这次的修改结果比较完美，地址不会改变，所以地址声明被移动到循环之外。地址内容是volatile,所以每次循环<br />之中它不断的被重新检查。</font>
		</p>
		<p>
				<font face="宋体" size="2">把一个const volatile变量作为参数传递给函数是合法的。如此的声明意味着函数不能改变变量的值，但是变量的<br />值却可以被另一个线程在任何时间改变掉。</font>
		</p>
		<p>
				<br />
				<font face="宋体" size="2">explicit关键字</font>
		</p>
		<p>
				<br />
				<font face="宋体" size="2">我们在编写应用程序的时候explicit关键字基本上是很少使用,它的作用是"禁止单参数构造函数"被用于自动型别转换,<br />其中比较典型的例子就是容器类型,在这种类型的构造函数中你可以将初始长度作为参数传递给构造函数.<br />例如:<br />你可以声明这样一个构造函数<br />class Array<br />{<br />public:<br /> explicit Array(int size);<br /> ......<br />};<br />在这里explicit关键字起着至关重要的作用,如果没有这个关键字的话,这个构造函数有能力将int转换成Array.一旦这种<br />情况发生,你可以给Array支派一个整数值而不会引起任何的问题,比如:<br />Array arr;<br />...<br />arr = 40;<br />此时,C++的自动型别转换会把40转换成拥有40个元素的Array,并且指派给arr变量,这个结果根本就不是我们想要的结果.如果<br />我们将构造函数声明为explicit,上面的赋值操作就会导致编译器报错,使我们可以及时发现错误.<br />需要注意的是:explicit同样也能阻止"以赋值语法进行带有转型操作的初始化";<br />例如:<br />Array arr(40);//正确<br />Array arr = 40;//错误</font>
		</p>
		<p>
				<font face="宋体" size="2">看一下以下两种操作:<br />X x;<br />Y y(x);//显式类型转换<br />另一种<br />X x;<br />Y y = x;//隐式类型转换</font>
		</p>
		<p>
				<font face="宋体" size="2">这两种操作存在一个小小的差别,第一种方式式通过显式类型转换,根据型别x产生了型别Y的新对象;第二种方式通过隐式转换<br />产生了一个型别Y的新对象.<br />explicit关键字的应用主要就是上面所说的构造函数定义种,参考该关键字的应用可以看看STL源代码,其中大量使用了该关键字</font>
		</p>
		<p>
				<font face="宋体" size="2">
				</font> </p>
		<p>
				<font face="宋体" size="2">__based关键字</font>
		</p>
		<p>
				<br />
				<font face="宋体" size="2">该关键字主要用来解决一些和共享内存有关的问题,它允许指针被定义为从某一点开始算的32位偏移值,而不是内存种的绝对位置<br />举个例子:</font>
		</p>
		<p>
				<font face="宋体" size="2">typedef struct tagDEMOSTRUCT {<br /> int a;<br /> char sz[10];<br />} DEMOSTRUCT, * PDEMOSTRUCT;</font>
		</p>
		<p>
				<font face="宋体" size="2">HANDLE hFileMapping = CreateFileMapping(...);<br />LPVOID lpShare = (LPDWORD)MapViewOfFile(...);</font>
		</p>
		<p>
				<font face="宋体" size="2">DEMOSTRUCT __based(lpShare)* lpDemo;</font>
		</p>
		<p>
				<font face="宋体" size="2">上面的例子声明了一个指针lpDemo,内部储存的是从lpShare开始的偏移值,也就是lpHead是以lpShare为基准的偏移值.<br />上面的例子种的DEMOSTRUCT只是随便定义的一个结构,用来代表任意的结构.</font>
		</p>
		<p>
				<font face="宋体" size="2">虽然__based指针使用起来非常容易,但是,你必须在效率上付出一定的代价.每当你用__based指针处理数据,CPU都必须<br />为它加上基地址,才能指向真正的位置.</font>
		</p>
		<p>
				<font face="宋体" size="2">在这里我只是介绍了几个并不时很常见的关键字的意义即用法,其他那些常见的关键字介绍他们的文章已经不少了在这里<br />就不再一一介绍了.希望这些内容能对大家有一定的帮助!</font>
		</p>
<img src ="http://www.cppblog.com/shaovie/aggbug/13993.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaovie/" target="_blank">崔少伟</a> 2006-10-22 09:57 <a href="http://www.cppblog.com/shaovie/articles/13993.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>困惑已久的问题</title><link>http://www.cppblog.com/shaovie/articles/13592.html</link><dc:creator>崔少伟</dc:creator><author>崔少伟</author><pubDate>Thu, 12 Oct 2006 01:56:00 GMT</pubDate><guid>http://www.cppblog.com/shaovie/articles/13592.html</guid><wfw:comment>http://www.cppblog.com/shaovie/comments/13592.html</wfw:comment><comments>http://www.cppblog.com/shaovie/articles/13592.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaovie/comments/commentRss/13592.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaovie/services/trackbacks/13592.html</trackback:ping><description><![CDATA[昨晚看书突然想起以前看到高质量C++编程里边说的内存泄露的问题有一处不明白..<br />今早赶紧上网找人求助..搞了半天终于搞明白了..(当时怎么想也想不通啊)<br />void getmem (char *p)<br />{<br />   p = new char[10];<br />}<br />int main ()<br />{<br />   char *str = NULL;<br />   getmem (str);<br />   strcpy (str,  "hello");<br />   printf (str);<br />   delete str;<br />}<br />错误:<br />编译器会给每个形参创建一个副本..而实际使用时也正是使用的这个副本.<br />所以 p == _p  = = str;    而开辟空间时实际是_p = new char[10]   而这时_p的值变了.<br />而p 的值没有变也就是说str 的值也没有变所以会导致strcpy错误.. 而这新开辟的这<br />块内存又没有得到释放.会导致内存泄露.<br />改正:<br />void getmem (char **p)<br />{<br />   *p = new char[10];<br />}<br />int main ()<br />{<br />   char *str = NULL;<br />   getmem (&amp;str);<br />   strcpy (str, "hello");<br />   printf (str);<br />   delete str;<br />}<br />分析:<br />此时 &amp;str == p == _p<br />str == *p = *_p<br /> 所以当 *_p = new char[10]时 str指向的地址也就变成了新内存的地址<br />主动分析:<br />当外部指针要想利用函数分配内存空间时,不能直接把指针的值传过去,因为函数用的是形参的副本.实际并不改变传过去的指针值.  要想改变它的指向就得让指向新内存的地址等于等于指针变量.这样就得采用指针的指针类型的形参.(实际起作用的是副本).然后把实参的地址传给形参.这样*_p实际改变的就是实能的指向了.<img src ="http://www.cppblog.com/shaovie/aggbug/13592.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaovie/" target="_blank">崔少伟</a> 2006-10-12 09:56 <a href="http://www.cppblog.com/shaovie/articles/13592.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ Optimizations(转载)</title><link>http://www.cppblog.com/shaovie/articles/13168.html</link><dc:creator>崔少伟</dc:creator><author>崔少伟</author><pubDate>Sat, 30 Sep 2006 02:07:00 GMT</pubDate><guid>http://www.cppblog.com/shaovie/articles/13168.html</guid><wfw:comment>http://www.cppblog.com/shaovie/comments/13168.html</wfw:comment><comments>http://www.cppblog.com/shaovie/articles/13168.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/shaovie/comments/commentRss/13168.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/shaovie/services/trackbacks/13168.html</trackback:ping><description><![CDATA[form (http://www.custard.org/~andrew/optimize.php) <br /><p>These optimizations are fairly easy to apply to existing code and in
some cases can result in big speedups. Remember the all-important maxim
though, <i>the fastest code is code that isn't called</i>.</p><table bgcolor="#fcfcdc" width="100%"><tbody><tr><td><h4>Use Initialization Lists</h4><p>
Always use initialization lists in constructors. For example, use
</p><p><code><font color="blue">
    TMyClass::TMyClass(const TData &amp;data) : m_Data(data)<br />
    {<br />
    }<br /></font></code></p><p>
rather than
</p><p><code><font color="blue">
    TMyClass::TMyClass(const TData &amp;data)<br />
    {<br />
             m_Data = data;<br />
    }<br /></font></code></p><p>
Without initialization lists, the variable's default constructor is
invoked behind-the-scenes prior to the class's constructor, then its
assignment operator is invoked. With initialization lists, only the
copy constructor is invoked. </p></td></tr></tbody></table><br /><br /><table bgcolor="#fcfcdc" width="100%"><tbody><tr><td><h4>Optimize For Loops</h4><p>
Whereever possible, count down to zero rather than up to n. For example, use
</p><p><code><font color="blue">
    for (i = n-1; i &gt;= 0; --i)<br /></font></code></p><p>
rather than
</p><p><code><font color="blue">
    for (i = 0; i &lt; n; ++i)<br /></font></code></p><p>
The test is done every iteration and it's faster to test against zero than anything else. Note also that
</p><p><code><font color="blue">
    ++i<br /></font></code></p><p>
is faster than
</p><p><code><font color="blue">
    i++<br /></font></code></p><p>
when it appears in the third part of the for loop statement. 
</p></td></tr></tbody></table><br /><br /><table bgcolor="#fcfcdc" width="100%"><tbody><tr><td><h4>Use 'int'</h4><p>
Always use the <code>int</code> data type instead of <code>char</code> or <code>short</code> wherever possible. <code>int</code> is always the native type for the machine.
</p></td></tr></tbody></table><br /><br /><table bgcolor="#fcfcdc" width="100%"><tbody><tr><td><h4>Make Local Functions Static</h4><p>
Always declare local functions as static, e.g., <br /></p><p><code><font color="blue">
    static void foo()<br /></font></code></p><p>
This means they will not be visible to functions outside the <code>.cpp</code> file, and some C++ compilers can take advantage of this in their optimizations.
</p></td></tr></tbody></table><br /><br /><table bgcolor="#fcfcdc" width="100%"><tbody><tr><td><h4>Optimize If Statements</h4><p>
Factor out jumps. For example, use<br /></p><p><code><font color="blue">
    bar();<br />
    if (condition)<br />
    {<br />
         undoBar();<br />
         foo();<br />
    }<br /></font></code></p><p>
rather than
</p><p><code><font color="blue">
    if (condition)<br />
    {<br />
         foo();<br />
    }<br />
    else<br />
    {<br />
         bar();<br />
    }<br /></font></code></p><p>
Use a profiler and good judgement to decide if undoing the bar() operation is faster than jumping. 
</p></td></tr></tbody></table><br /><br /><table bgcolor="#fcfcdc" width="100%"><tbody><tr><td><h4>Optimize Switch Statements</h4><p>
Put the most common cases first.
</p></td></tr></tbody></table><br /><br /><table bgcolor="#fcfcdc" width="100%"><tbody><tr><td><h4>Avoid Expensive Operations</h4><p>
Addition is cheaper than multiplication and multiplication is cheaper
than division. Factor out expensive operations whereever possible. </p></td></tr></tbody></table><br /><br /><table bgcolor="#fcfcdc" width="100%"><tbody><tr><td><h4>Initialize on Declaration</h4><p>
Whereever possible, initialize variables at the time they're declared. For example,
</p><p><code><font color="blue">
    TMyClass myClass = data; <br /></font></code></p><p>
is faster than 

</p><p><code><font color="blue">
    TMyClass myClass;<br />
    myClass = data;<br /></font></code></p><p>
Declaration then initialization invokes the object's default
constructor then its assignment operator. Initializing in the
declaration invokes only its copy constructor. </p></td></tr></tbody></table><br /><br /><table bgcolor="#fcfcdc" width="100%"><tbody><tr><td><h4>Pass By Reference</h4><p>
Always try to pass classes by reference rather than by value. For example, use 
</p><p><code><font color="blue">
    void foo(TMyClass &amp;myClass)<br /></font></code></p><p>
rather than
</p><p><code><font color="blue">
    void foo(TMyClass myClass)<br /></font></code></p><p></p></td></tr></tbody></table><br /><br /><table bgcolor="#fcfcdc" width="100%"><tbody><tr><td><h4>Delay Variable Declarations</h4><p>
Leave variable declarations right until the point when they're needed.
Remember that when a variable is declared its constructor is called.
This is wasteful if the variable is not used in the current scope. </p></td></tr></tbody></table><br /><br /><table bgcolor="#fcfcdc" width="100%"><tbody><tr><td><h4>Use 'op='</h4><p>
Wherever possible, use 'op=' in favour of 'op'. For example, use 
</p><p><code><font color="blue">
    myClass += value;<br /></font></code></p><p>
rather than
</p><p><code><font color="blue">
    myClass = myClass + value;
<br /></font></code></p><p>
The first version is better than the second because it avoids creating a temporary object. 
</p></td></tr></tbody></table><br /><br /><table bgcolor="#fcfcdc" width="100%"><tbody><tr><td><h4>Inline Small Functions</h4><p>
Small, performance critical functions should be inlined using the inline keyword, e.g., 
</p><p><code><font color="blue">
    inline void foo()<br /></font></code></p><p>
This causes the compiler to duplicate the body of the function in the
place it was called from. Inlining large functions can cause cache
misses resulting in slower execution times. </p></td></tr></tbody></table><br /><br /><h4>Use Nameless Classes</h4><p>
Whereever possible, use nameless classes. For example, 
</p><p><code><font color="blue">
    foo(TMyClass("abc"));<br /></font></code></p><p>
is faster than
</p><p><code><font color="blue">
    TMyClass myClass("abc");<br />
    foo(myClass);<br /></font></code></p><p>
because, in the first case, the parameter and the class share memory. 
</p><br /><img src ="http://www.cppblog.com/shaovie/aggbug/13168.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/shaovie/" target="_blank">崔少伟</a> 2006-09-30 10:07 <a href="http://www.cppblog.com/shaovie/articles/13168.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>