??xml version="1.0" encoding="utf-8" standalone="yes"?>久久99热这里只有精品66,青青青国产精品国产精品久久久久 ,97久久天天综合色天天综合色hdhttp://www.shnenglu.com/jack-wang/category/10923.htmlzh-cnMon, 11 Mar 2024 08:41:06 GMTMon, 11 Mar 2024 08:41:06 GMT60~译报错Q?lib/../lib64/crt1.oQ在函数‘_start’中(.text+0x20)对‘main’未定义的引?collect2: error: ld returned 1exit statushttp://www.shnenglu.com/jack-wang/archive/2024/03/05/230298.htmlTue, 05 Mar 2024 04:18:00 GMThttp://www.shnenglu.com/jack-wang/archive/2024/03/05/230298.htmlhttp://www.shnenglu.com/jack-wang/comments/230298.htmlhttp://www.shnenglu.com/jack-wang/archive/2024/03/05/230298.html#Feedback0http://www.shnenglu.com/jack-wang/comments/commentRss/230298.htmlhttp://www.shnenglu.com/jack-wang/services/trackbacks/230298.html

2024-03-05 12:18 发表评论
]]>
数点后保留N?/title><link>http://www.shnenglu.com/jack-wang/archive/2022/10/20/229446.html</link><dc:creator>王</dc:creator><author>王</author><pubDate>Thu, 20 Oct 2022 07:34:00 GMT</pubDate><guid>http://www.shnenglu.com/jack-wang/archive/2022/10/20/229446.html</guid><wfw:comment>http://www.shnenglu.com/jack-wang/comments/229446.html</wfw:comment><comments>http://www.shnenglu.com/jack-wang/archive/2022/10/20/229446.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/jack-wang/comments/commentRss/229446.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/jack-wang/services/trackbacks/229446.html</trackback:ping><description><![CDATA[<div>数点后保留2位数Q?br /><br />float x = 100.1234;</div><div>char buf[8] = { 0 };</div><div>::sprintf(buf, "%0.2lf", x);</div><img src ="http://www.shnenglu.com/jack-wang/aggbug/229446.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/jack-wang/" target="_blank">王</a> 2022-10-20 15:34 <a href="http://www.shnenglu.com/jack-wang/archive/2022/10/20/229446.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CMake报错Q?STREQUAL" "x86_64" Unknown arguments specifiedhttp://www.shnenglu.com/jack-wang/archive/2021/12/22/217888.htmlWed, 22 Dec 2021 08:24:00 GMThttp://www.shnenglu.com/jack-wang/archive/2021/12/22/217888.htmlhttp://www.shnenglu.com/jack-wang/comments/217888.htmlhttp://www.shnenglu.com/jack-wang/archive/2021/12/22/217888.html#Feedback0http://www.shnenglu.com/jack-wang/comments/commentRss/217888.htmlhttp://www.shnenglu.com/jack-wang/services/trackbacks/217888.html

"STREQUAL" "x86_64" Unknown arguments specified
解决Q?br />
if($ENV(COMPILING_TYPE) STREQUAL "x86_64")
改ؓ(f)Q?/span>
if(($ENV(COMPILING_TYPE)) STREQUAL "x86_64")


O了!



2021-12-22 16:24 发表评论
]]>
Centos中升UgccQ编译cmake报错Q‘make_unique’不是‘std’的成员Q?/title><link>http://www.shnenglu.com/jack-wang/archive/2020/01/10/217078.html</link><dc:creator>王</dc:creator><author>王</author><pubDate>Fri, 10 Jan 2020 07:11:00 GMT</pubDate><guid>http://www.shnenglu.com/jack-wang/archive/2020/01/10/217078.html</guid><wfw:comment>http://www.shnenglu.com/jack-wang/comments/217078.html</wfw:comment><comments>http://www.shnenglu.com/jack-wang/archive/2020/01/10/217078.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/jack-wang/comments/commentRss/217078.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/jack-wang/services/trackbacks/217078.html</trackback:ping><description><![CDATA[make_unique是包含在C++14中的Qgcc版本q低Q安装新版本gccQ比?.x <br /> 1、安装centos-release-scl <br />sudo yum install centos-release-scl <br /> 2、安装devtoolset <br />sudo yum install devtoolset-9-gcc* <br />Q如果想安装7.*版本的,改成devtoolset-7-gcc*Q? <br />3、激zd应的devtoolsetQ所以你可以一ơ安装多个版本的devtoolsetQ?br />需要的时候用下面以下命o(h)切换到对应的版本 <br />scl enable devtoolset-9 bash <br /> 4、查看gcc版本 gcc -v 昄?.x O了!<img src ="http://www.shnenglu.com/jack-wang/aggbug/217078.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/jack-wang/" target="_blank">王</a> 2020-01-10 15:11 <a href="http://www.shnenglu.com/jack-wang/archive/2020/01/10/217078.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>几个基本的库函数Q备?/title><link>http://www.shnenglu.com/jack-wang/archive/2010/09/14/126543.html</link><dc:creator>王</dc:creator><author>王</author><pubDate>Mon, 13 Sep 2010 16:24:00 GMT</pubDate><guid>http://www.shnenglu.com/jack-wang/archive/2010/09/14/126543.html</guid><wfw:comment>http://www.shnenglu.com/jack-wang/comments/126543.html</wfw:comment><comments>http://www.shnenglu.com/jack-wang/archive/2010/09/14/126543.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/jack-wang/comments/commentRss/126543.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/jack-wang/services/trackbacks/126543.html</trackback:ping><description><![CDATA[double pow(double x double k);<br>q回x的kơ方Q可以另k=1/n,则函数返回的是x的nơ方? <img src ="http://www.shnenglu.com/jack-wang/aggbug/126543.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/jack-wang/" target="_blank">王</a> 2010-09-14 00:24 <a href="http://www.shnenglu.com/jack-wang/archive/2010/09/14/126543.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>代码自动生成-宏带来的奇技淫y http://www.shnenglu.com/jack-wang/archive/2010/06/22/118512.htmlTue, 22 Jun 2010 15:54:00 GMThttp://www.shnenglu.com/jack-wang/archive/2010/06/22/118512.htmlhttp://www.shnenglu.com/jack-wang/comments/118512.htmlhttp://www.shnenglu.com/jack-wang/archive/2010/06/22/118512.html#Feedback1http://www.shnenglu.com/jack-wang/comments/commentRss/118512.htmlhttp://www.shnenglu.com/jack-wang/services/trackbacks/118512.html阅读全文

2010-06-22 23:54 发表评论
]]>
VS2005/2008 warning C4251 needs to have dll-interfacehttp://www.shnenglu.com/jack-wang/archive/2010/04/07/111826.htmlWed, 07 Apr 2010 00:57:00 GMThttp://www.shnenglu.com/jack-wang/archive/2010/04/07/111826.htmlhttp://www.shnenglu.com/jack-wang/comments/111826.htmlhttp://www.shnenglu.com/jack-wang/archive/2010/04/07/111826.html#Feedback1http://www.shnenglu.com/jack-wang/comments/commentRss/111826.htmlhttp://www.shnenglu.com/jack-wang/services/trackbacks/111826.html   E序中消除warning有两U方法:(x)消极一点不ȝ他,反正不是error:-)Q积极一点,则想办法L。去掉又用两U方法:(x)一U?pragma warning(disable: xxxx)Q眼不见Q心不烦(ch)Q另外就是找决问题的办法了?br>  今天做dll库时Q在struct中用CstlQ?br>  class CLASS_TEST
  {
    ...
  private:
    std::vector<MY_STRUCT> m_structs;
  }
  但是~译Ӟvs2005l出了warning C4251: 'CLASS_TEST::m_structs' : class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class ‘CLASS_TEST’的警告信息。费了很大的劲才解决掉,记录下来?/p>

  在头文g中,定义?br>#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif

  现在Q在变量m_structs前,dQ?br>template class MYDLL_API std::allocator<myStruct>;
template class MYDLL_API std::vector<myStruct, std::allocator<myStruct> >;
  q样Q即可以了?/p>

 

 



2010-04-07 08:57 发表评论
]]>
字节寚w详解http://www.shnenglu.com/jack-wang/archive/2010/03/17/109901.htmlWed, 17 Mar 2010 07:55:00 GMThttp://www.shnenglu.com/jack-wang/archive/2010/03/17/109901.htmlhttp://www.shnenglu.com/jack-wang/comments/109901.htmlhttp://www.shnenglu.com/jack-wang/archive/2010/03/17/109901.html#Feedback0http://www.shnenglu.com/jack-wang/comments/commentRss/109901.htmlhttp://www.shnenglu.com/jack-wang/services/trackbacks/109901.htmlhttp://blog.csdn.net/jszj/archive/2009/02/20/3915328.aspx

一.什么是字节寚w,Z么要寚w?
    C计算Z内存I间都是按照byte划分的,从理Z讲似乎对Mcd的变量的讉K可以从Q何地址开始,但实际情冉|在访问特定类型变量的时候经常在?定的内存地址讉KQ这需要各U类型数据按照一定的规则在空间上排列Q而不是顺序的一个接一个的排放Q这是寚w?br>    寚w的作用和原因Q各个硬件^台对存储I间的处理上有很大的不同。一些^台对某些特定cd的数据只能从某些特定地址开始存取。比如有些架构的CPU在访?一个没有进行对齐的变量的时候会(x)发生错误,那么在这U架构下~程必须保证字节寚w.其他q_可能没有q种情况Q但是最常见的是如果不按照适合其^台要求对 数据存放q行寚wQ会(x)在存取效率上带来损失。比如有些^台每ơ读都是从偶地址开始,如果一个int型(假设?2位系l)如果存放在偶地址开始的地方Q那 么一个读周期可以读32bitQ而如果存攑֜奇地址开始的地方Q就需?个读周期Qƈ对两ơ读出的l果的高低字节进行拼凑才能得到该32bit?据。显然在d效率上下降很多?/p>

?字节寚w对程序的影响:
    先让我们看几个例子吧(32bit,x86环境,gcc~译?:
讄构体如下定义Q?br>struct A
{
    int a;
    char b;
    short c;
};
struct B
{
    char b;
    int a;
    short c;
};
现在已知32位机器上各种数据cd的长度如?
char:1(有符hW号?   
short:2(有符hW号?   
int:4(有符hW号?   
long:4(有符hW号?   
float:4    double:8
那么上面两个l构大小如何?
l果?
sizeof(strcut A)gؓ(f)8
sizeof(struct B)的值却?2

l构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short型数据一?B也一?按理说A,B大小应该都是7字节?br>之所以出C面的l果是因为编译器要对数据成员在空间上q行寚w。上面是按照~译器的默认讄q行寚w的结?那么我们是不是可以改变编译器的这U默认对齐设|呢,当然可以.例如:
#pragma pack (2) /*指定?字节寚w*/
struct C
{
    char b;
    int a;
    short c;
};
#pragma pack () /*取消指定寚wQ恢复缺省对?/
sizeof(struct C)值是8?br>修改寚wgؓ(f)1Q?br>#pragma pack (1) /*指定?字节寚w*/
struct D
{
    char b;
    int a;
    short c;
};
#pragma pack () /*取消指定寚wQ恢复缺省对?/
sizeof(struct D)gؓ(f)7?br>后面我们再讲?pragma pack()的作?

?~译器是按照什么样的原则进行对齐的?
    先让我们看四个重要的基本概念Q?br>1.数据cd自n的对齐|(x)
  对于char型数据,其自w对齐gؓ(f)1Q对于short型ؓ(f)2Q对于int,float,doublecdQ其自n寚wgؓ(f)4Q单位字节?br>2.l构体或者类的自w对齐|(x)其成员中自n寚w值最大的那个倹{?br>3.指定寚w|(x)#pragma pack (value)时的指定寚w值value?br>4.数据成员、结构体和类的有效对齐|(x)自n寚w值和指定寚wg的那个倹{?br>?了这些|我们可以很方便的来讨论具体数据l构的成员和其自w的寚w方式。有效对齐值N是最l用来决定数据存攑֜址方式的|最重要。有效对齐NQ就?表示“寚w在N?#8221;Q也是说该数据?存放起始地址%N=0".而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址是?据结构的起始地址。结构体的成员变量要寚w排放Q结构体本n也要Ҏ(gu)自n的有效对齐值圆?是l构体成员变量占用总长度需要是对结构体有效寚w值的整数 倍,l合下面例子理解)。这样就不能理解上面的几个例子的g?br>例子分析Q?br>分析例子BQ?br>struct B
{
    char b;
    int a;
    short c;
};
?设B从地址I间0x0000开始排放。该例子中没有定义指定对齐|在笔者环境下Q该值默认ؓ(f)4。第一个成员变量b的自w对齐值是1Q比指定或者默认指?寚w?,所以其有效寚wgؓ(f)1Q所以其存放地址0x0000W合0x0000%1=0.W二个成员变量aQ其自n寚wgؓ(f)4Q所以有效对齐g?Q?所以只能存攑֜起始地址?x0004?x0007q四个连l的字节I间中,复核0x0004%4=0,且紧靠第一个变量。第三个变量c,自n寚wgؓ(f) 2Q所以有效对齐g?Q可以存攑֜0x0008?x0009q两个字节空间中Q符?x0008%2=0。所以从0x0000?x0009存放?都是B内容。再看数据结构B的自w对齐gؓ(f)其变量中最大对齐?q里是bQ所以就?Q所以结构体的有效对齐g?。根据结构体圆整的要求, 0x0009?x0000=10字节Q(10Q?Q%4Q?。所?x0000A?x000B也ؓ(f)l构体B所占用。故B?x0000?x000B 共有12个字?sizeof(struct B)=12;其实如果p一个就来说它已满_节对齐了, 因ؓ(f)它的起始地址?,因此肯定是对齐的,之所以在后面补充2个字?是因为编译器Z实现l构数组的存取效?试想如果我们定义了一个结构B的数l??么第一个结构v始地址?没有问题,但是W二个结构呢?按照数组的定?数组中所有元素都是紧挨着?如果我们不把l构的大补充ؓ(f)4的整数?那么下一 个结构的起始地址是0x0000A,q显然不能满结构的地址寚w?因此我们要把l构补充成有效对齐大的整数?其实诸如:对于char型数据,?自n寚wgؓ(f)1Q对于short型ؓ(f)2Q对于int,float,doublecdQ其自n寚wgؓ(f)4Q这些已有类型的自n寚wg是基于数l考虑??是因些类型的长度已知?所以他们的自n寚wg已知了.
同理,分析上面例子CQ?br>#pragma pack (2) /*指定?字节寚w*/
struct C
{
    char b;
    int a;
    short c;
};
#pragma pack () /*取消指定寚wQ恢复缺省对?/
W?一个变量b的自w对齐gؓ(f)1Q指定对齐gؓ(f)2Q所以,其有效对齐gؓ(f)1Q假设C?x0000开始,那么b存放?x0000Q符?x0000%1= 0;W二个变量,自n寚wgؓ(f)4Q指定对齐gؓ(f)2Q所以有效对齐gؓ(f)2Q所以顺序存攑֜0x0002?x0003?x0004?x0005四个q箋 字节中,W合0x0002%2=0。第三个变量c的自w对齐gؓ(f)2Q所以有效对齐gؓ(f)2Q顺序存?br>?x0006?x0007中,W合 0x0006%2=0。所以从0x0000?x00007共八字节存放的是C的变量。又C的自w对齐gؓ(f)4Q所以C的有效对齐gؓ(f)2。又8%2=0,C 只占?x0000?x0007的八个字节。所以sizeof(struct C)=8.

?如何修改~译器的默认寚w?
1.在VC IDE中,可以q样修改Q[Project]|[Settings],c/c++选项卡Category的Code Generation选项的Struct Member Alignment中修改,默认?字节?br>2.在编码时Q可以这样动态修改:(x)#pragma pack .注意:是pragma而不是progma.

?针对字节寚w,我们在编E中如何考虑?

    如果在编E的时候要考虑节约I间的话,那么我们只需要假定结构的首地址?,然后各个变量按照上面的原则进行排列即?基本的原则就是把l构中的变量按照 cd大小从小到大声明,量减少中间的填补空?q有一U就是ؓ(f)了以I间换取旉的效?我们昄的进行填补空间进行对?比如:有一U用空间换旉?法是昑ּ的插入reserved成员Q?br>         struct A{
           char a;
           char reserved[3];//使用I间换时?br>           int b;
}

reserved成员Ҏ(gu)们的E序没有什么意?它只是v到填补空间以辑ֈ字节寚w的目?当然即不加q个成员通常~译器也?x)给我们自动填补寚w,我们自己加上它只是v到显式的提醒作用.

?字节寚w可能带来的隐(zhn)?
    代码中关于对齐的隐?zhn)Q很多是隐式的。比如在强制cd转换的时候。例如:(x)
unsigned int i = 0x12345678;
unsigned char *p=NULL;
unsigned short *p1=NULL;

p=&i;
*p=0x00;
p1=(unsigned short *)(p+1);
*p1=0x0000;
最后两句代码,从奇数边界去讉Kunsignedshort型变量,昄不符合对齐的规定?br>在x86上,cM的操作只?x)?jing)响效率,但是在MIPS或者sparc上,可能是一个error,因ؓ(f)它们要求必须字节寚w.

?如何查找与字节对齐方面的问题:
如果出现寚w或者赋值问题首先查?br>1. ~译器的big little端设|?br>2. 看这U体pLw是否支持非寚w讉K
3. 如果支持看设|了寚w与否,如果没有则看讉K旉要加某些Ҏ(gu)的修饰来标志其特D访问操作?/p>

?相关文章:转自http://blog.csdn.net/goodluckyxl/archive/2005/10/17/506827.aspx

 ARM下的寚w处理
from DUI0067D_ADS1_2_CompLib

3.13 type  qulifiers

有部分摘自ARM~译器文档对齐部?/p>

寚w的?
1.__align(num)
   q个用于修改最高别对象的字节边界。在汇编中用LDRD或者STRD?br>   p用到此命令__align(8)q行修饰限制。来保证数据对象是相应对齐?br>   q个修饰对象的命令最大是8个字节限?可以?字节的对象进?字节
   寚w,但是不能?字节的对?字节寚w?br>   __align是存储类修改,他只修饰最高cd对象不能用于l构或者函数对象?br>  
2.__packed
  __packed是进行一字节寚w
  1.不能对packed的对象进行对?br>  2.所有对象的d讉K都进行非寚w讉K
  3.float?qing)包含float的结构联合及(qing)未用__packed的对象将不能字节寚w
  4.__packed对局部整形变量无影响
  5.强制由unpacked对象向packed对象转化是未定义,整Ş指针可以合法?br>  义ؓ(f)packed?br>     __packed int* p;  //__packed int 则没有意?br>  6.寚w或非寚wd讉K带来问题
  __packed struct STRUCT_TEST
 {
  char a;
  int b;
  char c;
 }  ;    //定义如下l构此时b的v始地址一定是不对齐的
         //在栈中访问b可能有问?因ؓ(f)栈上数据肯定是对齐访问[from CL]
//下面变量定义成全局静态不在栈?
static char* p;
static struct STRUCT_TEST a;
void Main()
{
 __packed int* q;  //此时定义成__packed来修饰当前q指向为非寚w的数据地址下面的访问则可以

 p = (char*)&a;         
 q = (int*)(p+1);     
 
 *q = 0x87654321;
/*  
得到赋值的汇编指o(h)很清?br>ldr      r5,0x20001590 ; = #0x12345678
[0xe1a00005]   mov      r0,r5
[0xeb0000b0]   bl       __rt_uwrite4  //在此处调用一个写4byte的操作函?
     
[0xe5c10000]   strb     r0,[r1,#0]   //函数q行4ơstrb操作然后q回保证了数据正的讉K
[0xe1a02420]   mov      r2,r0,lsr #8
[0xe5c12001]   strb     r2,[r1,#1]
[0xe1a02820]   mov      r2,r0,lsr #16
[0xe5c12002]   strb     r2,[r1,#2]
[0xe1a02c20]   mov      r2,r0,lsr #24
[0xe5c12003]   strb     r2,[r1,#3]
[0xe1a0f00e]   mov      pc,r14
*/

/*
如果q没有加__packed修饰则汇~出来指令是q样直接?x)导致奇地址处访问失?br>[0xe59f2018]   ldr      r2,0x20001594 ; = #0x87654321
[0xe5812000]   str      r2,[r1,#0]
*/

//q样可以很清楚的看到非对齐访问是如何产生错误?br>//以及(qing)如何消除非对齐访问带来问?br>//也可以看到非寚w讉K和对齐访问的指o(h)差异D效率问题
}
 


本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/jszj/archive/2009/02/20/3915328.aspx



2010-03-17 15:55 发表评论
]]>
Visual C++2010的c++语言四大新特?/title><link>http://www.shnenglu.com/jack-wang/archive/2010/03/15/109750.html</link><dc:creator>王</dc:creator><author>王</author><pubDate>Mon, 15 Mar 2010 10:25:00 GMT</pubDate><guid>http://www.shnenglu.com/jack-wang/archive/2010/03/15/109750.html</guid><wfw:comment>http://www.shnenglu.com/jack-wang/comments/109750.html</wfw:comment><comments>http://www.shnenglu.com/jack-wang/archive/2010/03/15/109750.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/jack-wang/comments/commentRss/109750.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/jack-wang/services/trackbacks/109750.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 10pt">转:(x)<a >http://blog.csdn.net/yincheng01/archive/2010/03/11/5367032.aspx</a><br><br>微Y卛_?010q??2日发布VS2010的正式版Q对于c++语言做了修改Q之更加符合c++标准?/p> <p style="FONT-SIZE: 10pt">下面对于微Y对于c++语言的修改做一下分析!</p> <p style="FONT-SIZE: 10pt">Lambda表达?/p> <p style="FONT-SIZE: 10pt">  很多~程~程语言都支持匿名函?anonymous function)。所谓匿名函敎ͼ是q个函数只有函数体,而没有函数名。Lambda表达式就是实现匿名函数的一U编E技巧,它ؓ(f)~写匿名函数提供了简明的函数式的句法。同hVisual Studio中的开发语aQVisual Basic和Visual C#早就实现了对Lambda表达式的支持Q终于Visual C++q次也不甘落后,在Visual Studio 2010中添加了对Lambda表达式的支持?br>  Lambda表达式得函数可以在使用的地方定义,q且可以在Lambda函数中用Lambda函数之外的数据。这׃ؓ(f)针对集合操作带来了很大的便利。在作用上,Lambda表达式类g函数指针和函数对象,Lambda表达式很好地兼顾了函数指针和函数对象的优点,却没有它们的~点。相对于函数指针或是函数对象复杂的语法Ş式,Lambda表达式用非常简单的语法可以实现同L(fng)功能Q降低了Lambda表达式的学习(fn)隑ֺQ避免了使用复杂的函数对象或是函数指针所带来的错误。我们可以看一个实际的例子Q?/p> <p style="FONT-SIZE: 10pt">view plaincopy to clipboardprint?<br>·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150<br>#include "stdafx.h"   <br>#include <algorithm>   <br>#include <iostream>   <br>#include <ostream>   <br>#include <vector>   <br>  <br>using namespace std;   <br>  <br>int _tmain(int argc, _TCHAR* argv[])   <br>{   <br>    vector<int> v;   <br>    for (int i = 0; i < 10; ++i) {   <br>        v.push_back(i);   <br>    }   <br>         for_each(v.begin(), v.end(), [] (int n) {   <br>        cout << n;   <br>        if (n % 2 == 0) {   <br>            cout << " even ";   <br>        } else {   <br>            cout << " odd ";   <br>        }   <br>    });   <br>    cout << endl;   <br>  <br>    return 0;   <br>}  <br>#include "stdafx.h"<br>#include <algorithm><br>#include <iostream><br>#include <ostream><br>#include <vector></p> <p style="FONT-SIZE: 10pt">using namespace std;</p> <p style="FONT-SIZE: 10pt">int _tmain(int argc, _TCHAR* argv[])<br>{<br>    vector<int> v;<br>    for (int i = 0; i < 10; ++i) {<br>        v.push_back(i);<br>    }<br>         for_each(v.begin(), v.end(), [] (int n) {<br>        cout << n;<br>        if (n % 2 == 0) {<br>            cout << " even ";<br>        } else {<br>            cout << " odd ";<br>        }<br>    });<br>    cout << endl;</p> <p style="FONT-SIZE: 10pt">    return 0;<br>}<br> </p> <p style="FONT-SIZE: 10pt">  q段代码循环遍历输出vector中的每一个数Qƈ判断q个数是奇数q是偶数。我们可以随时修改Lambda表达式而改变这个匿名函数的实现Q修改对集合的操作。在q段代码中,C++使用一对中括号“[]”来表CLambda表达式的开始,其后?#8221;(int n)”表示Lambda表达式的参数。这些参数将在Lambda表达式中使用到。ؓ(f)了体?x)Lambda表达式的z,我们来看看同L(fng)功能Q如何用函数对象实玎ͼ(x)<br> <br>view plaincopy to clipboardprint?<br>·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150<br>#include "stdafx.h"   <br>#include <algorithm>   <br>#include <iostream>   <br>#include <ostream>   <br>#include <vector>   <br>using namespace std;   <br>  <br>struct LambdaFunctor {   <br>    void operator()(int n) const {   <br>        cout << n << " ";   <br>        if (n % 2 == 0) {   <br>            cout << " even ";   <br>        } else {   <br>            cout << " odd ";   <br>        }   <br>  <br>    }   <br>};   <br>  <br>int _tmain(int argc, _TCHAR* argv[])   <br>{   <br>    vector<int> v;   <br>  <br>    for (int i = 0; i < 10; ++i) {   <br>        v.push_back(i);   <br>    }   <br>  <br>    for_each(v.begin(), v.end(), LambdaFunctor());   <br>    cout << endl;   <br>  <br>    return 0;   <br>}  <br>#include "stdafx.h"<br>#include <algorithm><br>#include <iostream><br>#include <ostream><br>#include <vector><br>using namespace std;</p> <p style="FONT-SIZE: 10pt">struct LambdaFunctor {<br>    void operator()(int n) const {<br>        cout << n << " ";<br>        if (n % 2 == 0) {<br>            cout << " even ";<br>        } else {<br>            cout << " odd ";<br>        }</p> <p style="FONT-SIZE: 10pt">    }<br>};</p> <p style="FONT-SIZE: 10pt">int _tmain(int argc, _TCHAR* argv[])<br>{<br>    vector<int> v;</p> <p style="FONT-SIZE: 10pt">    for (int i = 0; i < 10; ++i) {<br>        v.push_back(i);<br>    }</p> <p style="FONT-SIZE: 10pt">    for_each(v.begin(), v.end(), LambdaFunctor());<br>    cout << endl;</p> <p style="FONT-SIZE: 10pt">    return 0;<br>}<br> <br>  通过比较我们可以发玎ͼLambda表达式的语法更加z,使用h更加单高?/p> <p style="FONT-SIZE: 10pt">静态断astatic_assert</p> <p style="FONT-SIZE: 10pt">  在之前的C++标准C++03中,我们可以使用两种断言Q?br>  • 使用预处理中的条件编译和#error指o(h)Q可以在预处理阶D|查一些编译条?br>  • 可以使用宏assert来进行运行时(g)查,以确保程序逻辑的正?/p> <p style="FONT-SIZE: 10pt">  但?errorҎ(gu)是非常烦(ch)琐的Qƈ且不能够Ҏ(gu)板参数进行检查,因ؓ(f)模板实例化是在编译时q行Q?errorҎ(gu)是在预处理阶D进行的。而assert宏是在运行时q行(g)查。不隑֏玎ͼ我们~少了一样东西,那就是可用于在编译时(g)查的工具。于是,静态断a应运而生?/p> <p style="FONT-SIZE: 10pt">  在新的C++标准C++0x中,加入了对静态断a的支持,引入了新的关键字static_assert来表C静态断a。用静态断aQ我们可以在E序的编译时期检一些条件是否成立,q个Ҏ(gu)在调试模板函数的模板参数时特别有用。在~译的时候,模板函数实例化,q时我们可以用静态断aL试模板函数的参数是否按照我们的设计拥有合适的倹{例如下面这D代码:(x)</p> <p style="FONT-SIZE: 10pt">view plaincopy to clipboardprint?<br>·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150<br>template <int N> struct Kitten {   <br>    static_assert(N < 2, "Kitten<N> requires N < 2.");   <br>};   <br>  <br>int main() {   <br>    Kitten<1> peppermint;   <br>    Kitten<3> jazz;   <br>  <br>   return 0;   <br>}  <br>template <int N> struct Kitten {<br>    static_assert(N < 2, "Kitten<N> requires N < 2.");<br>};</p> <p style="FONT-SIZE: 10pt">int main() {<br>    Kitten<1> peppermint;<br>    Kitten<3> jazz;</p> <p style="FONT-SIZE: 10pt">   return 0;<br>}<br> <br>  当我们在dC使用“1”d例化Kittenq个l构体时Q在~译的时候,静态断astatic_assert?x)测试参数N的|当N的值小?时就?x)生一个断a错误Qƈ相应的调试帮助信息输出?#8220;Error List”H口中,q样E序员就可以寚w题快速定位,解决问题更加方便了?br> </p> <p style="FONT-SIZE: 10pt"><br>? static_assert断言?qing)其输?/p> <p style="FONT-SIZE: 10pt"><br>  另外Q静态断aq带来很多其他的优势。例如静态断a在编译时q行处理Q不?x)生Q何运行时ȝ间和旉上的开销Q这׃得它比assert宏具有更好的效率。另外比较重要的一个特性是如果断言p|Q它?x)生有意义且充分的诊断信息Q帮助程序员快速解决问题?/p> <p style="FONT-SIZE: 10pt">  auto关键?/p> <p style="FONT-SIZE: 10pt">  在C++0x中,auto关键字的意义发生了改变。从Visual C++ 2010开始,auto关键字将用于指引~译器根据变量的初始值来军_变量的数据类型。换句话_(d)我们可以把auto当成一U新的数据类型,它可?#8220;从初始化?initialize)中推导出所代表的变量的真正cd”。这U对auto关键字的使用方式可以大大消除当前替代方式所D的冗长和易出错的代码。我们看一个实际的例子Q?/p> <p style="FONT-SIZE: 10pt">view plaincopy to clipboardprint?<br>·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150<br>#include <iostream>   <br>#include <map>   <br>#include <ostream>   <br>#include <regex>   <br>#include <string>   <br>using namespace std;   <br>using namespace std::tr1;   <br>  <br>int main() {   <br>    map<string, string> m;   <br>  <br>    const regex r("(<a href="file://w/">\\w</a>+) (<a href="file://w/">\\w</a>+)");   <br>  <br>    for (string s; getline(cin, s); ) {   <br>        smatch results;   <br>        if (regex_match(s, results, r)) {   <br>            m[results[1]] = results[2];   <br>        }   <br>    }   <br>    for (auto i = m.begin(); i != m.end(); ++i) {   <br>        cout << i->second << " are " << i->first << endl;   <br>    }   <br>  <br>    return 0;   <br>}  <br>#include <iostream><br>#include <map><br>#include <ostream><br>#include <regex><br>#include <string><br>using namespace std;<br>using namespace std::tr1;</p> <p style="FONT-SIZE: 10pt">int main() {<br>    map<string, string> m;</p> <p style="FONT-SIZE: 10pt">    const regex r("(<a href="file://w/">\\w</a>+) (<a href="file://w/">\\w</a>+)");</p> <p style="FONT-SIZE: 10pt">    for (string s; getline(cin, s); ) {<br>        smatch results;<br>        if (regex_match(s, results, r)) {<br>            m[results[1]] = results[2];<br>        }<br>    }<br>    for (auto i = m.begin(); i != m.end(); ++i) {<br>        cout << i->second << " are " << i->first << endl;<br>    }</p> <p style="FONT-SIZE: 10pt">    return 0;<br>}<br> <br>  在这D代码中Q我们用auto关键字来代替了真正的数据cdmap<string, string>::iteratorQ这使得整个代码自然而简z?/p> <p style="FONT-SIZE: 10pt">  另外Q跟其他数据cd一P我们也可以对auto关键字进行修饎ͼ例如dconstQ指?*)Q左值引?&)Q右值引?&&){等Q编译器?x)根据a(chn)utocd所代表的真正的数据来决定这些修饰的具体含义?/p> <p style="FONT-SIZE: 10pt">  Z兼容一些旧有的C++代码Q我们可以?Zc:autoq个~译器选项Q来告诉~译器是采用auto关键字的原有定义q是在新标准C++0x中的定义?/p> <p style="FONT-SIZE: 10pt">叛_引?/p> <p style="FONT-SIZE: 10pt">  作ؓ(f)最重要的一语aҎ(gu),叛_引?rvalue references)被引入到 C++0x中。我们可以通过操作W?#8220;&&”来声明一个右值引用,原先在C++中?#8220;&”操作W声明的引用现在被称为左值引用?</p> <p style="FONT-SIZE: 10pt">int a;<br>int& a_lvref = a;  // 左值引?/p> <p style="FONT-SIZE: 10pt">int b;<br>int&& b_rvref = b;  // 叛_应?br>  左值引用和叛_引用的表现行ؓ(f)基本一_(d)它们唯一的差别就是右值引用可以绑定到一个(f)时对?叛_?上,而左值引用不可以。例如:(x) </p> <p style="FONT-SIZE: 10pt">int& a_lvref = int();      // error C2440: 'initializing' : cannot convert from 'int' to 'int &'    <br>int&& b_rvref = int();  // OK!<br>  在第一行代码中Q我们将一个(f)时对象int()l定C个左值引用,生一个编译错误。而在W二行中Q我们将临时对象l定到右值引用,可以顺利通过~译?/p> <p style="FONT-SIZE: 10pt">  叛_是无名的数据,例如函数的返回g般说来就是右倹{当对右D行操作的时候,叛_本w往往没有必要保留Q因此在某些情况下可以直?#8220;Ud”之。通过叛_引用,E序可以明确的区分出传入的参数是否ؓ(f)叛_|从而避免了不必要的拯Q程序的效率也就得到了提高。我们考虑一个简单的数据交换的小E序Q从中来体会(x)叛_引用所带来的效率提升。我们可以写一个函数swap来实C个变量值的交换Q?/p> <p style="FONT-SIZE: 10pt">view plaincopy to clipboardprint?<br>·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150<br>template <class T> swap(T& a, T& b)   <br>{   <br>    T tmp(a);   // tmp对象创徏后,我们拥有了a的两份拷?nbsp;  <br>    a = b;      // 现在我们拥有b的两份拷?nbsp;  <br>    b = tmp;    // 现在我们拥有a的两份拷?nbsp;  <br>}  <br>template <class T> swap(T& a, T& b)<br>{<br>    T tmp(a);   // tmp对象创徏后,我们拥有了a的两份拷?br>    a = b;      // 现在我们拥有b的两份拷?br>    b = tmp;    // 现在我们拥有a的两份拷?br>} <br>  在这D代码中Q虽然我们只是ؓ(f)了进行简单的数据交换Q但是却执行了多ơ对象拷贝。这些对象的拯操作Q特别是当这些对象比较大的时候,无疑?x)?jing)响程序的效率?/p> <p style="FONT-SIZE: 10pt">  那么Q如果用右值引用如何实现呢Q?/p> <p style="FONT-SIZE: 10pt">view plaincopy to clipboardprint?<br>·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150<br>#include "stdafx.h"   <br>  <br>template <class T>    <br>T&& move(T&& a)   <br>{   <br>    return a;   <br>}   <br>  <br>template <class T> void swap(T& a, T& b)   <br>{   <br>    T tmp(move(a)); // 对象a被移动到对象tmpQa被清I?nbsp;  <br>    a = move(b);    // 对象b被移动到对象aQb被清I?nbsp;  <br>    b = move(tmp);  // 对象tmp被移动到对象b   <br>}   <br>  <br>int _tmain(int argc, _TCHAR* argv[])   <br>{   <br>    int a = 1;   <br>    int b = 2;   <br>    swap(a, b);   <br>  <br>   return 0;   <br>}  <br>#include "stdafx.h"</p> <p style="FONT-SIZE: 10pt">template <class T> <br>T&& move(T&& a)<br>{<br>    return a;<br>}</p> <p style="FONT-SIZE: 10pt">template <class T> void swap(T& a, T& b)<br>{<br>    T tmp(move(a)); // 对象a被移动到对象tmpQa被清I?br>    a = move(b);    // 对象b被移动到对象aQb被清I?br>    b = move(tmp);  // 对象tmp被移动到对象b<br>}</p> <p style="FONT-SIZE: 10pt">int _tmain(int argc, _TCHAR* argv[])<br>{<br>    int a = 1;<br>    int b = 2;<br>    swap(a, b);</p> <p style="FONT-SIZE: 10pt">   return 0;<br>}<br> </p> <p style="FONT-SIZE: 10pt"><br>  在这D重新实现的代码中,我们使用了一个move()函数来代替对象的赋值操作符“=”,move()只是单地接受一个右值引用或者左值引用作为参敎ͼ然后直接q回相应对象的右值引用。这一q程不会(x)产生拯(Copy)操作Q而只?x)将源对象移?Move)到目标对象?/p> <p style="FONT-SIZE: 10pt">  正是拯(Copy)和移?Move)的差别,使得叛_引用成为C++0x中最Ȁ动h心的新特性之一。从实践角度Ԍ它能够完是解决C++中长久以来ؓ(f)人所诟病的(f)时对象的效率问题。从语言本nԌ它健全了C++中的引用cd在左值右值方面的~陷。从库设计者的角度Ԍ它给库设计者又带来了一把利器。而对于广大的库用者而言Q不动一兵一卒便能够获得“免费?#8221;效率提升?/p> <p style="FONT-SIZE: 10pt">  在Visual Studio 2010中,因ؓ(f)有了对这些C++0x新特性的支持Q重新点燃了E序员们对C++的热情。C++重振雄风Q指日可待!</p> <p style="FONT-SIZE: 10pt"><br>本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/yincheng01/archive/2010/03/11/5367032.aspx</a></p> <p style="FONT-SIZE: 10pt"> </p> <img src ="http://www.shnenglu.com/jack-wang/aggbug/109750.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/jack-wang/" target="_blank">王</a> 2010-03-15 18:25 <a href="http://www.shnenglu.com/jack-wang/archive/2010/03/15/109750.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>今天工作中突然提CstdcallQ我都有些忘了,差点被主问?/title><link>http://www.shnenglu.com/jack-wang/archive/2010/01/21/106195.html</link><dc:creator>王</dc:creator><author>王</author><pubDate>Thu, 21 Jan 2010 15:43:00 GMT</pubDate><guid>http://www.shnenglu.com/jack-wang/archive/2010/01/21/106195.html</guid><wfw:comment>http://www.shnenglu.com/jack-wang/comments/106195.html</wfw:comment><comments>http://www.shnenglu.com/jack-wang/archive/2010/01/21/106195.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/jack-wang/comments/commentRss/106195.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/jack-wang/services/trackbacks/106195.html</trackback:ping><description><![CDATA[ <br /> <font size="2">比如 我们有这样一个C函数<br />#include<stdio.h><br />long test(int a,int b)<br />{<br />    a = a + 1;<br />    b = b + 100;<br />    return a + b;<br />}<br /><br />写成32位汇~就是这?br />;//////////////////////////////////////////////////////////////////////////////////////////////////////<br />.386<br />.module flat,stdcall           ;q里我们用stdcall 是函数参数 压栈的时候从最后一个开始压Q和被调用函数负责清?br />option casemap:none            ;区分大小?br /><br />includelib msvcrt.lib          ;q里是引入类?#160;相当?#160;#include<stdio.h>?#160;      <br />printf  PROTO C:DWORD,:VARARG  ;q个是声明一下我们要用的函数_(d)到时?#160;汇编E序?x)自动到msvcrt.lib里面扄?#160;<br />                                ;:VARARG 表后面的参数不确?#160;因ؓ(f)C是q样的printf(const char *, ...);<br />                               ;q样的函数要注意 不是被调用函数负责清?#160;因ؓ(f)它本w不知道有多个参数<br />                               ;而是有调用者负责清?#160; 下面?x)详l说?br />.data<br />szTextFmt  BYTE '%d',0        ;q个是用来类型{换的Q跟C的一?字符用字节类?br />a          dword 1000         ;假设<br />b          dword 2000         ;处理数值都用双?#160;没有int 跟long 的区?br /><br />;/////////////////////////////////////////////////////////////////////////////////////////<br />.code<br /><br />_test proc A:DWORD,B:DWORD <br />      push ebp<br />      mov  ebp,esp<br />      mov  eax,dword ptr ss:[ebp+8]<br />      add  eax,1<br />      mov  edx,dword ptr ss:[ebp+0Ch]<br />      add  edx,100<br />      add  eax,edx<br />      pop  ebp      <br />      retn 8<br />_test endp<br /><br />_main proc <br />      push dword ptr ds:b       ;反汇~我们看到的b׃是b了而是一个[*****]数字 dword ptr 是我们在ds(数据D?把[*****]<br />                                ;开始的一个双字长数值取出来<br />      push dword ptr ds:a       ;跟她对应的还?#160;byte ptr ****是取一个字节出?#160;比如q样 mov  al,byte ptr ds:szTextFmt <br />                                ;把 % 取出?#160;而不包括 d<br />      call _test                  <br />      push eax                  ;假设push eax的地址?#215;××××<br />      push offset szTextFmt<br />      call printf<br />      add  esp,8<br />      ret             <br />_main endp<br />end  _main<br /><br />;////////////////////////////////////////////////////////////// 下面介绍堆栈的变?br />首先要明白的?#160;操作堆栈D?#160;ss 只能?#160;esp或ebp寄存?#160;其他的寄存器eax ebx edx{都不能够用 ?#160;esp永远指向堆栈栈顶 ebp用来 在堆栈段<br /><br />里面d<br />push 指o(h)是压?#160;ESP=ESP-4<br />pop  指o(h)是出?#160;ESP=ESP+4<br />我们假设main函数一开始堆栈定?#160;ESP=400<br />push dword ptr ds:b                 ;ESP-4=396 ->里面的值就?#160;2000 是b的数?br />push dword ptr ds:a                 ;ESP-4=392 ->里面的值就?#160;1000 是a的数?br />call test                           ;ESP-4=388Q?gt;里面的数值是什么?q个太重要了 是我们用来找游戏函数的原理所在?br />                                                 里面的数值就是call test 指o(h)下一条指令的地址Q?gt;即push eax的地址×××××<br /><br />Ctest函数里面<br /><br />push ebp                           ;ESP-4=384->里面保存了当前ebp的?#160;而不是把ebp清零<br />mov  ebp,esp                       ;q里ESPQ?84没变化了,但是 ebp=esp=384,Z么要q样做呢 因ؓ(f)我们要用ebp到堆栈里面找参数<br />mov  eax,dword ptr ss:[ebp+8]      ;反汇~是q样?#160;xZ么a是[ebp+8]?br />                                   ;我们往上看看堆栈里地址392处就保存着a的?#160;q里ebp=384 加上8正好是392?br />                                   ;q样把传递过来的1000拿了出来eax=1000<br />add  eax,1                         ;相当?#160;a+1?#160;eax=1001<br />mov  edx,dword ptr ss:[ebp+0Ch]    ; 0Ch=12 一样道理这里指向堆栈的地址?84+12=396 是2000?#160;edx=2000<br />add  edx,100                       ;相当?#160;b+100 edx=2100<br />add  eax,edx                       ;eax=eax+edxQ?001Q?100Q?101 q里eax已经保存了最l的l果?#160;<br />                                   ;因ؓ(f)win32汇编一般用eaxq回l果 所以如果最l结果不是在eax里面的话 q要把它攑ֈeax<br />                                   ;比如假设我的l果保存在变量nRet里面 最后还是要q样 mov eax,dword ptr nRet<br />pop  ebp                           ;ESP=384+4=388 而保存在栈顶384的?#160;保存?#160;ebp?#160;x复ebp原来的?#160;                      <br />                                   ;因ؓ(f)一开始我们就把ebp的值压栈了Qmov ebp,esp已经改变了ebp的|q里恢复是保证了堆栈^?br />retn  8                            ;ESP+8->396 q里retn是由pȝ调用?#160;我们不用?#160;pȝ?x)自动把EIP指针指向 原来的call的下一条指?br />                                   ;׃是系l自动恢复了call那里的压栈所?#160;真正q回到的时候ESP+4是恢复了call压栈的堆?br />                                   ;Cq个时?#160;ESP=400 是函数调用开始的堆栈Q就是说函数调用前跟函数调用后的堆栈是一L(fng)<br />                                   ;q就是堆栈^?#160;<br />׃我们用stdcall上面retn 8是被调用者负责恢复堆栈的意思了Q函数test是被调用者,所以负责把堆栈?,call 那里是系l自动恢复的<br /><br />push eax                ;ESP-4=396->里面保存了eax的?101<br />                        ;上面已经看到了eax保存着q回|我们要把它传lprintf也是通过堆栈传?#160;      <br />push offset szTextFmt   ;ESP-4=392->里面保存了szTextFmt的地址 也就是C里面的指?#160;实际上没有什么把字符串传递的Q我们传的都是地址<br />                        ;无论是在汇编或C 所以在汇编里没有什么字W串cd 用最多的是DWORD。嘿嘿游戏里面传递参?#160;单多?br />call printf             ;ESP-4=388->里面保存了下一条指令的地址<br />add  esp,8              ;ESP+8=400 恢复了调用printf前的堆栈状?br />                        ;上面说了׃printf后面参数?VARARG q样的类型是有调用者恢复堆栈的 所以printf里面没有retn 8之类的指?br />                        ;q是p用者负责清?#160;main是调用?#160;所以下面一句就?#160;add esp,8 把堆栈恢复到调用printf之前<br />                        ;而call printf那里的压?#160;是由pȝ做的 恢复的工作也是系l完?#160;我们不用?#160;只是知道里面保存是返回地址够  <br /><br />                      ;?br />ret                     ;main 函数q回 其他的事情是pȝ自动搞定 我们不用?#160;d完成<br /></font> <img src ="http://www.shnenglu.com/jack-wang/aggbug/106195.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/jack-wang/" target="_blank">王</a> 2010-01-21 23:43 <a href="http://www.shnenglu.com/jack-wang/archive/2010/01/21/106195.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>最快速度扑ֈ内存泄漏http://www.shnenglu.com/jack-wang/archive/2010/01/21/106191.htmlThu, 21 Jan 2010 15:14:00 GMThttp://www.shnenglu.com/jack-wang/archive/2010/01/21/106191.htmlhttp://www.shnenglu.com/jack-wang/comments/106191.htmlhttp://www.shnenglu.com/jack-wang/archive/2010/01/21/106191.html#Feedback0http://www.shnenglu.com/jack-wang/comments/commentRss/106191.htmlhttp://www.shnenglu.com/jack-wang/services/trackbacks/106191.html 原帖Q?a >http://blog.csdn.net/i_like_cpp/archive/2007/06/28/1669962.aspx
作者:(x)许式?2006q?1月某?/font>

内存理是C++E序员的痛。我的《内存管理变革》系列就是试图讨论更为有效的内存理方式Q以杜绝Q或减少Q内存泄漏,减轻C++E序员的负担。由于工作忙的缘故,q个pd目前未完Q暂停?br /> 
q篇短文我想换个方式Q讨Z下如何以最快的速度扑ֈ内存泄漏?br /> 
认是否存在内存泄漏
我们知道QMFCE序如果(g)到存在内存泄漏Q退出程序的时候会(x)在调试窗口提醒内存泄漏。例如:(x)

class CMyApp : public CWinApp
{
public:
   BOOL InitApplication()
   {
       int* leak = new int[10];
       return TRUE;
   }
};
产生的内存泄漏报告大体如下:(x)

Detected memory leaks!
Dumping objects ->
c:\work\test.cpp(186) : {52} normal block at 0x003C4410, 40 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
q挺好。问题是Q如果我们不喜欢MFCQ那么难道就没有办法Q或者自己做Q?

呵呵Q这不需要。其实,MFC也没有自己做。内存泄漏检的工作是VC++的Cq行库做的。也是_(d)只要你是VC++E序员,都可以很方便地检内存泄漏。我们还是给个样例:(x)

#include <crtdbg.h>

inline void EnableMemLeakCheck()
{
   _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
}

void main()
{
   EnableMemLeakCheck();
   int* leak = new int[10];
}
 q行Q提醒:(x)不要按Ctrl+F5Q按F5Q,你将发现Q生的内存泄漏报告与MFCcMQ但有细节不同,如下Q?/font>

Detected memory leaks!
Dumping objects ->
{52} normal block at 0x003C4410, 40 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
Z么呢Q看下面?/font>

定位内存泄漏׃哪一句话引v?br />你已l发现程序存在内存泄漏。现在的问题是,我们要找泄漏的根源?/font>

一般我们首先确定内存泄漏是׃哪一句引赗在MFC中,q一点很Ҏ(gu)。你双击内存泄漏报告的文字,或者在DebugH口中按F4QIDE帮你定位到甌该内存块的地斏V对于上例,也就是这一句:(x)

   int* leak = new int[10];

q多多少对你分析内存泄漏有点帮助。特别地Q如果这个new仅对应一条deleteQ或者你把delete漏写Q,q将很快可以认问题的症l?

我们前面已经看到Q不使用MFC的时候,生成的内存泄漏报告与MFC不同Q而且你立d现按F4不灵。那么难道MFC做了什么手脚?

其实不是Q我们来模拟下MFC做的事情。看下例Q?

inline void EnableMemLeakCheck()
{
   _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
}

#ifdef _DEBUG
#define new   new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif

void main()
{
   EnableMemLeakCheck();
   int* leak = new int[10];
}

再运行这个样例,你惊喜地发现Q现在内存泄漏报告和MFC没有M分别了?/font>

快速找到内存泄?br />单确定了内存泄漏发生在哪一行,有时候ƈ不够。特别是同一个new对应有多处释攄情Ş。在实际的工E中Q以下两U情况很典型Q?

创徏对象的地Ҏ(gu)一个类工厂QClassFactoryQ模式。很多甚臛_部类实例由同一个new创徏。对于此Q定位到了new出对象的所在行基本没有多大帮助?
 
COM对象。我们知道COM对象采用Reference Countl护生命周期。也是_(d)对象new的地方只有一个,但是Release的地方很多,你要一个个排除?
那么Q有什么好办法Q可以迅速定位内存泄漏?

{:(x)有?/font>

在内存泄漏情况复杂的时候,你可以用以下Ҏ(gu)定位内存泄漏。这是我个h认ؓ(f)通用的内存泄漏追t方法中最有效的手Dc(din)?/font>

我们再回头看看crtdbg生成的内存泄漏报告:(x)

Detected memory leaks!
Dumping objects ->
c:\work\test.cpp(186) : {52} normal block at 0x003C4410, 40 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
除了产生该内存泄漏的内存分配语句所在的文g名、行号ؓ(f)Q我们注意到有一个比较陌生的信息Q{52}。这个整数g表了什么意思呢Q?/font>

其实Q它代表了第几次内存分配操作。象q个例子Q{52}代表了第52ơ内存分配操作发生了泄漏。你可能要说Q我只newq一ơ,怎么?x)是W?2ơ?q很Ҏ(gu)理解Q其他的内存甌操作在C的初始化q程调用的呗?)

有没有可能,我们让程序运行到W?2ơ内存分配操作的时候,自动停下来,q入调试状态?所q,crtdbg实提供了这L(fng)函数Q即 long _CrtSetBreakAlloc(long nAllocID)。我们加上它Q?/font>

inline void EnableMemLeakCheck()
{
   _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
}

#ifdef _DEBUG
#define new   new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif

void main()
{
   EnableMemLeakCheck();
   _CrtSetBreakAlloc(52);
   int* leak = new int[10];
}
你发玎ͼE序q行?int* leak = new int[10]; 一句时Q自动停下来q入调试状态。细l体?x)一下,你可以发玎ͼq种方式你获得的信息q比在程序退出时获得文g名及(qing)行号有h(hun)值得多。因为报告泄漏文件名?qing)行P你获得的只是静态的信息Q然而_CrtSetBreakAlloc则是把整个现场恢复,你可以通过对函数调用栈分析Q我发现很多Z?fn)惯看函数调用栈Q如果你属于q种情况Q我强烈推荐你去补上q一课,因ؓ(f)它太重要了)以及(qing)其他在线调试技巧,来分析生内存泄漏的原因。通常情况下,q种分析Ҏ(gu)可以?分钟内找到肇事者?/font>

当然Q_CrtSetBreakAlloc要求你的E序执行q程是可q原的(多次执行q程的内存分配顺序不?x)发生变化)。这个假讑֜多数情况下成立。不q,在多U程的情况下Q这一Ҏ(gu)旉以保证?/font>

 


附加说明Q?br />对“内存管理”相关的技术感兴趣Q这里可以看到我的所有关于内存管理的文章?/font>

 

本文来自CSDN博客Q{载请标明出处Q?/font> http://blog.csdn.net/i_like_cpp/archive/2007/06/28/1669962.aspx



2010-01-21 23:14 发表评论
]]>
Ʒ99þaaaһëƬ| 91Ʒɫ۾þ| þ޾ƷVA| þĻƵ| ޹㽶ˬAVƬþ| þþþ޾Ʒվ| Ʒþþ| ˳wwwþþ| 鶹һ99þþþ| 99þùۺϾƷˮ | þþþþþۺձ| þþþø߳ۺӰԺ| þۺϾɫۺϾƷ| ձþþվ| 91þþžվ| ҰAVþһ| 99þþƷѹƬ| AëƬþþƷ| ƷþþþĻһ| ƷþþþþóAV| þþžѾƷ6| þþþӰԺС | þ㽶߿ۿ | 9391ƷۺϾþ㽶 | ȾþùŷһƷ| 97þþþ| ݺɫۺϾþ| Ʒþþþù3d| ŷҹͽþþ | ˾þþƷ| Ʒþþһ| þþþþྫƷֱ | þþþӰԺС| þۺϾþþ| Ʒþþþþ| 51þҹɫƷ| ھƷþþþ| þþƷŷ| þþƷwww| ݺݾþۺ˲| ξþ99Ʒþþþþ|