﻿<?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++博客-A Za, A Za, Fighting...-随笔分类-Z_小小知识点</title><link>http://www.cppblog.com/Joe/category/16957.html</link><description>坚信：勤能补拙</description><language>zh-cn</language><lastBuildDate>Tue, 24 May 2011 16:47:28 GMT</lastBuildDate><pubDate>Tue, 24 May 2011 16:47:28 GMT</pubDate><ttl>60</ttl><item><title>#if 0 /#if 1</title><link>http://www.cppblog.com/Joe/archive/2011/05/24/147036.html</link><dc:creator>simplyzhao</dc:creator><author>simplyzhao</author><pubDate>Tue, 24 May 2011 07:24:00 GMT</pubDate><guid>http://www.cppblog.com/Joe/archive/2011/05/24/147036.html</guid><wfw:comment>http://www.cppblog.com/Joe/comments/147036.html</wfw:comment><comments>http://www.cppblog.com/Joe/archive/2011/05/24/147036.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Joe/comments/commentRss/147036.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Joe/services/trackbacks/147036.html</trackback:ping><description><![CDATA[当注释掉大块代码时，使用"#if 0"比使用"/**/"要好，因为用"/**/"做大段的注释要防止被注释掉的代码中有嵌套的"/**/",这会导致注释掉的代码区域不是你想要的范围，当被注释掉的代码很大时容易出现这种情况，特别是过一段时间后又修改该处代码时更是如此。 
<p><span style="font-size: 14px">　　在这里顺便对条件编译（#ifdef, #else, #endif, #if等）进行说明。以下分3种情况：</span></p>
<p><span style="font-size: 14px">　　1. 情况1：<br />　　#ifdef _XXXX<br />　　&nbsp;&nbsp;&nbsp; ...程序段1...<br />　　#else<br />　　&nbsp;&nbsp;&nbsp; ...程序段2...<br />　　#endif<br />　　这表明如果标识符_XXXX已被#define命令定义过则对程序段1进行编译；否则对程序段2进行编译。</span></p>
<p><span style="font-size: 14px">　　2:情况2：<br />　　#ifndef _XXXX<br />　　&nbsp;&nbsp;&nbsp; ...程序段1...<br />　　#else<br />　　&nbsp;&nbsp;&nbsp; ...程序段2...<br />　　#endif<br />　　这里使用了#ifndef，表示的是if not def。当然是和#ifdef相反的状况（如果没有定义了标识符_XXXX，那么执行程序段1，否则执行程序段2）。</span></p>
<p><span style="font-size: 14px">　　3：情况3：<br />　　#if 常量<br />　　&nbsp;&nbsp;&nbsp; ...程序段1...<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#else<br />　　&nbsp;&nbsp;&nbsp; ...程序段2...<br />　　#endif<br />　　这里表示，如果常量为真（非0，随便什么数字，只要不是0），就执行程序段1，否则执行程序段2。<br /><br /></span></p><img src ="http://www.cppblog.com/Joe/aggbug/147036.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Joe/" target="_blank">simplyzhao</a> 2011-05-24 15:24 <a href="http://www.cppblog.com/Joe/archive/2011/05/24/147036.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>operator new/delete与 new/delete operator</title><link>http://www.cppblog.com/Joe/archive/2011/05/24/147028.html</link><dc:creator>simplyzhao</dc:creator><author>simplyzhao</author><pubDate>Tue, 24 May 2011 06:12:00 GMT</pubDate><guid>http://www.cppblog.com/Joe/archive/2011/05/24/147028.html</guid><wfw:comment>http://www.cppblog.com/Joe/comments/147028.html</wfw:comment><comments>http://www.cppblog.com/Joe/archive/2011/05/24/147028.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Joe/comments/commentRss/147028.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Joe/services/trackbacks/147028.html</trackback:ping><description><![CDATA[<p>C++中的operator new与new operator，看上去挺像的两姐妹，却有天壤之别。 
<p>operator new 
<p>（1） 只分配所要求的空间，不调用相关对象的构造函数。当无法满足所要求分配的空间时，则 
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt;如果有new_handler，则调用new_handler，否则 
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt;如果没要求不抛出异常（以nothrow参数表达），则执行bad_alloc异常，否则 
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt;返回0 
<p>（2） 可以被重载 
<p>（3） 重载时，返回类型必须声明为void* 
<p>（4） 重载时，第一个参数类型必须为表达要求分配空间的大小（字节），类型为size_t 
<p>（5） 重载时，可以带其它参数 
<p>new operator 
<p>（1） 调用operator new分配足够的空间，并调用相关对象的构造函数 
<p>（2） 不可以被重载 
<p>相应地，operator delete与delete operator有相似的特性。 
<p>举个例子 
<p><code>class X <br />{<br />public:<br />&#8230;&#8230;&#8230;&#8230;<br />&nbsp;&nbsp;&nbsp; static void* operator new(size_t size)<br />{<br />&nbsp;&nbsp;&nbsp; return ::operator new(size);<br />}<br />static void operator delete(void* pointee)<br />{<br />&nbsp;&nbsp;&nbsp; ::operator delete(pointee);<br />}<br />&#8230;&#8230;&#8230;&#8230;<br />};<br />X* px = new X();<br /></code>
<p>该行代码中的new为new operator，它将调用类X中的operator new，为该类的对象分配空间，然后调用当前实例的构造函数。 
<p><code>delete px;</code> 
<p>该行代码中的delete为delete operator，它将调用该实例的析构函数，然后调用类X中的operator delete，以释放该实例占用的空间。 
<p>new operator与delete operator的行为是不能够也不应该被改变，这是C++标准作出的承诺。而operator new与operator delete和C语言中的malloc与free对应，只负责分配及释放空间。但使用operator new分配的空间必须使用operator delete来释放，而不能使用free，因为它们对内存使用的登记方式不同。反过来亦是一样。 
<p>你可以重载operator new和operator delete以实现对内存管理的不同要求，但你不能重载new operator或delete operator以改变它们的行为。 
<p>当重载operator new时，可以提供更多的参数，在new一个对象时，通过在关键字new后的括号传递额外的参数。比如以下的类 
<p><code>class A <br />{<br />public:<br />&nbsp;&nbsp;&nbsp; &#8230;&#8230;&#8230;&#8230;<br />&nbsp;&nbsp;&nbsp; static void* operator new(size_t size, const string&amp; example)<br />{<br />&nbsp;&nbsp;&nbsp; cout &lt;&lt; example &lt;&lt; endl;<br />&nbsp;&nbsp;&nbsp; return ::operator new(size);<br />}<br />&#8230;&#8230;&#8230;&#8230;<br />};<br />A* pa = new (&#8220;This will be printed out in operator new&#8221;) A();<br /></code>
<p>新标准的C++允许以这样的方式传递一个名为nothrow的参数，以表明当为该对象分配空间失败时，不抛出异常，而是返回0，以兼容旧标准new的行为。比如 
<p><code>class B {};<br />B* pb = new (nothrow) B();<br /></code>
<p>当然这只能对那些使用默认operator new操作符的类。对已经重载了operator new的类（比如上面的X和A），如果不声明能接受nothrow参数，自然无法享受C++标准带来的礼物。 <br /><br />--------<br /><br /></p>
<p><font color="#000000" face="Verdana">我们经常看到这么一句话： operator new 可以重载， placement new 不可重载。其实此处所说的不可重载应该是指全局的 placement new 不可重载，对于类域中的 placement new 是可以重载的，而且只要重载了任何一种形式的 operator new 都应该顺便重载 placement new ， 即 void * operator new(std::size_t count, void *ptr) 。 </font></p>
<p><font color="#000000" face="Verdana">操作符重载一般用于特定类型，名字解析过程同一般的函数重载。 Operator new 由于其特殊性，编译器提供了默认提供 6 种全局重载形式，同时还允许用户提供自定义的全局 operator new ，其参数甚至可以和全局版本一样，除全局 placement new 外。对于类域，任何形式的 new 都是可以重载的，包括 placement new 形式。 </font></p>
<p><font color="#000000" face="Verdana">&nbsp; </font></p>
<p><font color="#000000" face="Verdana">全局的 operator new( 函数 ) 有六种重载形式 </font></p>
<p><font color="#000000" face="Verdana">void *operator new(std::size_t count) </font></p>
<p><font color="#000000" face="Verdana">&nbsp;&nbsp;&nbsp; throw(std::bad_alloc);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 一般的版本 </font></p>
<p><font color="#000000" face="Verdana">&nbsp; </font></p>
<p><font color="#000000" face="Verdana">void *operator new(std::size_t count,&nbsp;&nbsp; // 兼容早版本的 new </font></p>
<p><font color="#000000" face="Verdana">&nbsp;&nbsp;&nbsp; const std::nothrow_t&amp;) throw();&nbsp;&nbsp; // 内存分配失败不会抛出异常 </font></p>
<p><font color="#000000" face="Verdana">&nbsp; </font></p>
<p><font color="#000000" face="Verdana">void *operator new(std::size_t count, void *ptr) throw();&nbsp; //placement 版本 </font></p>
<p><font color="#000000" face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></p>
<p><font color="#000000" face="Verdana">void *operator new[](std::size_t count)&nbsp; // </font></p>
<p><font color="#000000" face="Verdana">&nbsp;&nbsp;&nbsp; throw(std::bad_alloc); </font></p>
<p><font color="#000000" face="Verdana">&nbsp; </font></p>
<p><font color="#000000" face="Verdana">void *operator new[](std::size_t count,&nbsp; // </font></p>
<p><font color="#000000" face="Verdana">&nbsp;&nbsp;&nbsp; const std::nothrow_t&amp;) throw(); </font></p>
<p><font color="#000000" face="Verdana">&nbsp; </font></p>
<p><font color="#000000" face="Verdana">void *operator new[](std::size_t count, void *ptr) throw(); </font></p>
<p><font color="#000000" face="Verdana">&nbsp; </font></p>
<p><font color="#000000" face="Verdana">重载 operator new 规则 </font></p>
<p><font color="#000000" face="Verdana">重载 operator new 的参数个数是可以任意的 , 只需要保证第一个参数为 size_t, 返回类型为 void * 即可 , 而且其重载的参数类型也不必包含自定义类型 . 更一般的说 , operator new 的重载更像是一个函数的重载 , 而不是一个操作符的重载 . 如： </font></p>
<p><font color="#000000" face="Verdana">&nbsp; </font></p>
<p><font color="#000000" face="Verdana">全局重载示例： </font></p>
<p><font color="#000000" face="Verdana">void* operator new(size_t size)&nbsp; // 重载成功 </font></p>
<p><font color="#000000" face="Verdana">{ </font></p>
<p><font color="#000000" face="Verdana">&nbsp;&nbsp; printf("global new\n"); </font></p>
<p><font color="#000000" face="Verdana">&nbsp;&nbsp; return malloc(size); </font></p>
<p><font color="#000000" face="Verdana">&nbsp;&nbsp; //return ::operator new(size);&nbsp; // 递归调用提示 (warning) </font></p>
<p><font color="#000000" face="Verdana">} </font></p>
<p><font color="#000000" face="Verdana">&nbsp; </font></p>
<p><font color="#000000" face="Verdana">//void *operator new(std::size_t size, void *ptr) // 无法重载 </font></p>
<p><font color="#000000" face="Verdana">//{ </font></p>
<p><font color="#000000" face="Verdana">//&nbsp;&nbsp;&nbsp;&nbsp; printf("global new\n"); </font></p>
<p><font color="#000000" face="Verdana">//&nbsp;&nbsp;&nbsp;&nbsp; return ::operator new(size,ptr); </font></p>
<p><font color="#000000" face="Verdana">//} </font></p>
<p><font color="#000000" face="Verdana">&nbsp; </font></p>
<p><font color="#000000" face="Verdana">void * operator new(size_t size, const std::nothrow_t&amp; e) // 重载成功 , 递归调用提示 (warning) </font></p>
<p><font color="#000000" face="Verdana">{ </font></p>
<p><font color="#000000" face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("global new\n"); </font></p>
<p><font color="#000000" face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ::operator new(size, e); </font></p>
<p><font color="#000000" face="Verdana">} </font></p>
<p><font color="#000000" face="Verdana">&nbsp; </font></p>
<p><font color="#000000" face="Verdana">一般形式的 operator new 重载示例： </font></p>
<p><font color="#000000" face="Verdana">void * operator new(size_t size, int x, int y, int z) </font></p>
<p><font color="#000000" face="Verdana">{ </font></p>
<p><font color="#000000" face="Verdana">&nbsp;&nbsp;&nbsp; ... </font></p>
<p><font color="#000000" face="Verdana">} </font></p>
<p><font color="#000000" face="Verdana">X * pX = new (1, 2, 3) X; </font></p>
<p><font color="#000000" face="Verdana">&nbsp; </font></p>
<p><font color="#000000" face="Verdana">char data[1000][sizeof(foo)]; </font></p>
<p><font color="#000000" face="Verdana">inline void* operator new(size_t size, int n) </font></p>
<p><font color="#000000" face="Verdana">{ </font></p>
<p><font color="#000000" face="Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return data[n]; </font></p>
<p><font color="#000000" face="Verdana">} </font></p>
<p><font color="#000000" face="Verdana">就可以使用这样有趣的语法来创建对象 : </font></p>
<p><font color="#000000" face="Verdana">foo *p=new(6) foo(); // 把对象创建在 data 的第六个单元上&nbsp;</font>&nbsp;</p><img src ="http://www.cppblog.com/Joe/aggbug/147028.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Joe/" target="_blank">simplyzhao</a> 2011-05-24 14:12 <a href="http://www.cppblog.com/Joe/archive/2011/05/24/147028.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>#ifdef __cplusplus 是什么意思？</title><link>http://www.cppblog.com/Joe/archive/2011/05/22/146936.html</link><dc:creator>simplyzhao</dc:creator><author>simplyzhao</author><pubDate>Sun, 22 May 2011 09:57:00 GMT</pubDate><guid>http://www.cppblog.com/Joe/archive/2011/05/22/146936.html</guid><wfw:comment>http://www.cppblog.com/Joe/comments/146936.html</wfw:comment><comments>http://www.cppblog.com/Joe/archive/2011/05/22/146936.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Joe/comments/commentRss/146936.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Joe/services/trackbacks/146936.html</trackback:ping><description><![CDATA[<div id="cnblogs_post_body">
<p>时常在cpp的代码之中看到这样的代码: </p>
<p>#ifdef __cplusplus <br />extern "C" { <br />#endif </p>
<p>//一段代码 </p>
<p>#ifdef __cplusplus <br />} <br />#endif <br />　　这样的代码到底是什么意思呢？首先，__cplusplus是cpp中的自定义宏，那么定义了这个宏的话表示这是一段cpp的代码，也就是说，上面的代码的含义是:如果这是一段cpp的代码，那么加入extern "C"{和}处理其中的代码。 </p>
<p>　　要明白为何使用extern "C"，还得从cpp中对函数的重载处理开始说起。在c++中，为了支持重载机制，在编译生成的汇编码中，要对函数的名字进行一些处理，加入比如函数的返回类型等等.而在C中，只是简单的函数名字而已，不会加入其他的信息.也就是说:C++和C对产生的函数名字的处理是不一样的. </p>
<p>　　比如下面的一段简单的函数，我们看看加入和不加入extern "C"产生的汇编代码都有哪些变化: </p>
<p>int f(void) <br />{ <br />return 1; <br />} <br />　　在加入extern "C"的时候产生的汇编代码是: </p>
<p>.file "test.cxx" <br />.text <br />.align 2 <br />.globl _f <br />.def _f; .scl 2; .type 32; .endef <br />_f: <br />pushl %ebp <br />movl %esp， %ebp <br />movl $1， %eax <br />popl %ebp <br />ret <br />　　但是不加入了extern "C"之后 </p>
<p>.file "test.cxx" <br />.text <br />.align 2 <br />.globl __Z1fv <br />.def __Z1fv; .scl 2; .type 32; .endef <br />__Z1fv: <br />pushl %ebp <br />movl %esp， %ebp <br />movl $1， %eax <br />popl %ebp <br />ret <br />　　两段汇编代码同样都是使用gcc -S命令产生的，所有的地方都是一样的，唯独是产生的函数名，一个是_f，一个是__Z1fv。 </p>
<p>　　明白了加入与不加入extern "C"之后对函数名称产生的影响，我们继续我们的讨论:为什么需要使用extern "C"呢？C++之父在设计C++之时，考虑到当时已经存在了大量的C代码，为了支持原来的C代码和已经写好C库，需要在C++中尽可能的支持C，而extern "C"就是其中的一个策略。 </p>
<p>　　试想这样的情况:一个库文件已经用C写好了而且运行得很良好，这个时候我们需要使用这个库文件，但是我们需要使用C++来写这个新的代码。如果这个代码使用的是C++的方式链接这个C库文件的话，那么就会出现链接错误.我们来看一段代码:首先，我们使用C的处理方式来写一个函数，也就是说假设这个函数当时是用C写成的: </p>
<p>//f1.c <br />extern "C" <br />{ <br />void f1() <br />{ <br />return; <br />} <br />} <br />　　编译命令是:gcc -c f1.c -o f1.o 产生了一个叫f1.o的库文件。再写一段代码调用这个f1函数: </p>
<p>// test.cxx <br />//这个extern表示f1函数在别的地方定义，这样可以通过 <br />//编译，但是链接的时候还是需要 <br />//链接上原来的库文件. <br />extern void f1(); </p>
<p>int main() <br />{ <br />f1(); </p>
<p>return 0; <br />} <br />　　通过gcc -c test.cxx -o test.o 产生一个叫test.o的文件。然后，我们使用gcc test.o f1.o来链接两个文件，可是出错了，错误的提示是: </p>
<p>test.o(.text + 0x1f):test.cxx: undefine reference to 'f1()' <br />　　也就是说，在编译test.cxx的时候编译器是使用C++的方式来处理f1()函数的，但是实际上链接的库文件却是用C的方式来处理函数的，所以就会出现链接过不去的错误:因为链接器找不到函数。 </p>
<p>　　因此，为了在C++代码中调用用C写成的库文件，就需要用extern "C"来告诉编译器:这是一个用C写成的库文件，请用C的方式来链接它们。 </p>
<p>　　比如，现在我们有了一个C库文件，它的头文件是f.h，产生的lib文件是f.lib，那么我们如果要在C++中使用这个库文件，我们需要这样写: </p>
<p>extern "C" <br />{ <br />#include "f.h" <br />} <br />　　回到上面的问题，如果要改正链接错误，我们需要这样子改写test.cxx: </p>
<p>extern "C" <br />{ <br />extern void f1(); <br />} </p>
<p>int main() <br />{ <br />f1(); </p>
<p>return 0; <br />} <br />　　重新编译并且链接就可以过去了. </p>
<p>　　总结 </p>
<p>　　C和C++对函数的处理方式是不同的.extern "C"是使C++能够调用C写作的库文件的一个手段，如果要对编译器提示使用C的方式来处理函数的话，那么就要使用extern "C"来说明。</p></div><script type="text/javascript">
if ($ != jQuery) {
	$ = jQuery.noConflict();
}
var isLogined = false;
var cb_blogId = 17173;
var cb_entryId = 512552;
var cb_blogApp = "stonecrazyking";
var cb_blogUserGuid = "7f4f360b-63cf-dd11-9e4d-001cf0cd104b";
var cb_entryCreatedDate = '2006/9/23 12:28:00';
</script><img src ="http://www.cppblog.com/Joe/aggbug/146936.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Joe/" target="_blank">simplyzhao</a> 2011-05-22 17:57 <a href="http://www.cppblog.com/Joe/archive/2011/05/22/146936.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>