键盘的咏叹调

常用链接

统计

最新评论

2010年1月28日 #

[zz]解决链接错误:error LNK2001: 无法解析的外部符号 __iob

该错误主要是由于静态库在VC6编译而主程序在VC2005编译,大家用的CRT不同。解决办法,代码中增加

#ifdef __cplusplus
extern "C"
#endif
FILE _iob[3] = {__iob_func()[0], __iob_func()[1], __iob_func()[2]};

此错误的产生根源:
在VC6的stdio.h之中有如下定义

_CRTIMP extern FILE _iob[];
#define stdin (&_iob[0])
#define stdout (&_iob[1])
#define stderr (&_iob[2])

stdin、stdout、stderr是通过查_iob数组得到的。所以,VC6编译的程序、静态库只要用到了printf、scanf之类的函数,都要链接_iob数组。

而在vc2005中,stdio.h中变成了

_CRTIMP FILE * __cdecl __iob_func(void);
#define stdin (&__iob_func()[0])
#define stdout (&__iob_func()[1])
#define stderr (&__iob_func()[2])

_iob数组不再是显式的暴露出来了,需要调用__iob_func()函数获得。所以vc6的静态库链接VC2005的C运行库就会找不到_iob数组.
通过重新定义
FILE _iob[3] = {__iob_func()[0], __iob_func()[1], __iob_func()[2]};
就把vc6需要用到的_iob数组搞出来了

posted @ 2010-01-28 11:39 键盘的咏叹调 阅读(2652) | 评论 (0)编辑 收藏

2009年11月18日 #

[zz]An introduction to debugging in MSVC++ using Pseudoregisters

Introduction

Let's start with the reason why I wrote this article. One day, a colleague asked me to help him debug a problem he had. So I was watching him stepping in his code, when I noticed the following line:

Collapse
int test = GetLastError();

He did this, because he wanted to know the error code, if the previous function failed. He was adding this line every time he wanted to know the error code. I advised him to remove all those lines and use the @ERR pseudoregister in his watch window. He didn't know what it was and asking around in the office, a lot of other people didn't. So I came up with this article for people who have never heard of pseudoregisters.

What is a pseudoregister anyway?

A pseudoregister is not an actual hardware register, but is displayed as though it were a hardware register. With a pseudoregister, you can see and use certain values (error codes, thread information block...) in the debugger.

Let's have a look at the @ERR pseudoregister. Fire up your debugger with your favourite home-written application. Put a breakpoint in your code so that the debugger will break execution. Open the watch window if it isn't already (do this by right clicking on some empty toolbar space, and select "Watch" from this list). Add @ERR in this watch window. You should see 0 in the Value column. Now step through your code, and watch this value. It will always show the GetLastError() number for the current thread. So if something goes wrong in your code, this value will change.

If you want to test this, but your code doesn't have any errors, I advise to put some in (but don't forget to remove them afterwards). You can insert something like this:

Collapse
FILE *fp = fopen("c:\\a_file_that_does_not_exist.txt", "r");

If you step over this line, you'll see that the @ERR value changed to 2. Go to Tools->Error Lookup to see what this error value means ("The system cannot find the file specified" if you were wondering). Lazy bums like me, and smart lads / lasses like you can change the @ERR pseudoregister to @ERR,hr . Doing this will change the value of the pseudoregister to the error string. Now you even don't have to lookup the error. I leave the @ERR,hr in the watch window all the time.

Conditional Expressions

Pseudoregisters can also be used in conditional expressions. To try this out, put following lines after the fopen:

Collapse
if (fp)
{
fclose(fp);
}

Put a breakpoint on the if (fp) line. Go to Edit->Breakpoints (or press Alt-F9). Select the breakpoint you just inserted and press the "Condition" button. Here, you can enter the @ERR==2 condition. Now start the debugger. The debugger will break on this breakpoint if fopen() failed because it couldn't find the file. If the file does exist, the debugger won't break, even if it encountered another error (say error 4: could not open the file). Try this out by running the code (not stepping) after creating, and deleting the "a_file_that_does_not_exist.txt" file on c:\.

Just for the very curious (and otherwise totally irrelevant to this article) : what does @ERR do? How does it get the error number? As it turns out, @ERR does exactly the same thing as GetLastError() does. These functions have a whopping 3 lines of assembly code:

Collapse
mov eax,fs:[00000018h] 
mov eax,dword ptr [eax+34h]
ret

So @ERR grabs the DWORD at offset 0x34 in the thread environment block pointed to by fs:[18h].

The @TIB pseudoregister

The @ERR pseudoregister is not the only one that exists. Another important pseudoregister is @TIB. This is the thread information block for the current thread and is extremely helpful in multi-threaded debugging. If you place a breakpoint in a function that is called by multiple threads, the debugger will break execution every time no matter which thread passes the breakpoint. Even if you're stepping through your code, the debugger can jump to the breakpoint if another thread called the function. To solve this, you'll need to do the following. If execution breaks in the thread you want, add @TIB in the watch window. You will see some value like "0x7ffa6000" or "2147115008" in regular display. Go to the breakpoint menu (Alt-F9) and select the breakpoint. You can now add the @TIB==0x7ffa6000 condition filter. Doing this, the debugger will only break execution for this thread. All other threads using the same function will not result in a break.

This doesn't work in Windows 98 though. For Windows 98, you'll need to look at the Intel CPU FS register, which is unique for each thread. You can use the expression @FS==value

Complete list of pseudoregisters

Pseudoregister

Description

@ERR

Last error value; the same value returned by the GetLastError() API function

@TIB

Thread information block for the current thread; necessary because the debugger doesn't handle the "FS:0" format

@CLK

Undocumented clock register; usable only in the Watch window

@EAX, @EBX, @ECX, @EDX, @ESI, @EDI, @EIP, @ESP, @EBP, @EFL

Intel CPU registers

@CS, @DS, @ES, @SS, @FS, @GS

Intel CPU segment registers

@ST0, @ST1, @ST2, @ST3, @ST4, @ST5, @ST6, @ST7

Intel CPU floating-point registers

posted @ 2009-11-18 09:49 键盘的咏叹调 阅读(216) | 评论 (0)编辑 收藏

2009年8月12日 #

关于CRT的全局变量构造的问题

历史原因 项目中已有的代码有了很多全局变量,
之前这些变量相安无事,
直到需要添加一个内存管理的功能,而这个功能也需要一个全局变量,但是这个全局变量必须在所有其他全局变量之前执行初始化。

最开始使用#pragma section(SECNAME,long,read)的方法,把某个函数加入到某个section中,因为CRT是按照section的字母序执行的,这个方法
在exe中执行的很好,不幸的是我们是在一个dll中,这个方法不奏效。

最后查看msdn,写道:如果是使用dll,使用#pragma init_seg
#pragma init_seg(compiler)
_CRTIMP2 MemoryManager MemMnger;
这样,初始化工作在编译器初始化的时候就执行了,连断点都断不到了


posted @ 2009-08-12 11:47 键盘的咏叹调 阅读(371) | 评论 (0)编辑 收藏

2009年8月7日 #

[zz]visual studio中的Regex

正则表达式是查找和替换文本模式的简洁和灵活的表示法。Visual Studio 中使用的正则表达式是 Visual C++ 6.0 中使用的、具有简化语法的表达式的超集。

在“查找”、“在文件中查找”或“在文件中替换”对话框中,可使用下列正则表达式来改进和扩展搜索。

注意???在将下列任何表达式用作搜索条件的一部分之前,必须在“查找”、“在文件中查找”和“在文件中替换”对话框中选择“使用”复选框。

可使用下列表达式匹配搜索字符串中的字符或数字:

表达式 语法 说明
任一字符 . 匹配除换行符外的任何一个字符。
最多 0 项或更多 * 匹配前面表达式的 0 个或更多搜索项。
最多一项或更多 + 匹配前面表达式的至少一个搜索项。
最少 0 项或更多 @ 匹配前面表达式的 0 个或更多搜索项,匹配尽可能少的字符。
最少一项或更多 # 匹配前面表达式的一个或更多搜索项,匹配尽可能少的字符。
重复 n ^n 匹配前面表达式的 n 个搜索项。例如,[0-9]^4 匹配任意 4 位数字的序列。
字符集 [] 匹配 [] 内的任何一个字符。要指定字符的范围,请列出由短划线 (-) 分隔的起始字符和结束字符,如 [a-z] 中所示。
不在字符集中的字符 [^...] 匹配跟在 ^ 之后的不在字符集中的任何字符。
行首 ^ 将匹配定位到行首。
行尾 $ 将匹配定位到行尾。
词首 < 仅当词在文本中的此位置开始时才匹配。
词尾 > 仅当词在文本中的此位置结束时才匹配。
分组 () 将子表达式分组。
| 匹配 OR 符号 (|) 之前或之后的表达式。). 最常用在分组中。例如,(sponge|mud) bath 匹配“sponge bath”和“mud bath”。
转义符 \ 匹配跟在反斜杠 (\) 后的字符。这使您可以查找在正则表达式表示法中使用的字符,如 { 和 ^。例如,\^ 搜索 ^ 字符。
带标记的表达式 {} 标记括号内的表达式所匹配的文本。
n 个带标记的文本 \n 在“查找”或“替换”表达式中,指示第 n 个带标记的表达式所匹配的文本,其中 n 是从 1 至 9 的数字。

在“替换”表达式中,\0 插入整个匹配的文本。

右对齐字段 \(w,n) 在“替换”表达式中,将字段中第 n 个带标记的表达式右对齐至少 w 字符宽。
左对齐字段 \(-w,n) 在“替换”表达式中,将字段中第 n 个带标记的表达式左对齐至少 w 字符宽。
禁止匹配 ~(X) 当 X 出现在表达式中的此位置时禁止匹配。例如,real~(ity)????匹配“realty”和“really”中的“real”,而不匹配“reality”中的“real”。
字母数字字符 :a 匹配表达式
([a-zA-Z0-9])。
字母字符 :c 匹配表达式
([a-zA-Z])。
十进制数 :d 匹配表达式
([0-9])。
十六进制数 :h 匹配表达式
([0-9a-fA-F]+)。
标识符 :i 匹配表达式
([a-zA-Z_$][a-zA-Z0-9_$]*)。
有理数 :n 匹配表达式
(([0-9]+.[0-9]*)| ([0-9]*.[0-9]+)| ([0-9]+)).
带引号的字符串 :q 匹配表达式 (("[^"]*")| ('[^']*'))
字母字符串 :w 匹配表达式
([a-zA-Z]+)
十进制整数 :z 匹配表达式
([0-9]+)。
转义符 \e Unicode U+001B。
Bell \g Unicode U+0007。
退格符 \h Unicode U+0008。
换行符 \n 匹配与平台无关的换行符。在“替换”表达式中,插入换行符。
制表符 \t 匹配制表符,Unicode U+0009。
Unicode 字符 \x#### 或 \u#### 匹配 Unicode 值给定的字符,其中 #### 是十六进制数。可以用 ISO 10646 代码点或两个提供代理项对的值的 Unicode 代码点指定基本多语种平面(即一个代理项)外的字符。

下表列出按标准 Unicode 字符属性进行匹配的语法。两个字母的缩写词与 Unicode 字符属性数据库中所列的一样。可将这些指定为字符集的一部分。例如,表达式 [:Nd:Nl:No] 匹配任何种类的数字。

表达式 语法 说明
大写字母 :Lu 匹配任何一个大写字母。例如,:Luhe 匹配“The”但不匹配“the”。
小写字母 :Ll 匹配任何一个小写字母。例如,:Llhe 匹配“the”但不匹配“The”。
词首大写字母 :Lt 匹配将大写字母和小写字母结合的字符,例如,Nj 和 Dz。
修饰符字母 :Lm 匹配字母或标点符号,例如逗号、交叉重音符和双撇号,用于表示对前一字母的修饰。
其他字母 :Lo 匹配其他字母,如哥特体字母 ahsa。
十进制数 :Nd 匹配十进制数(如 0-9)和它们的双字节等效数。
字母数字 :Nl 匹配字母数字,例如罗马数字和表意数字零。
其他数字 :No 匹配其他数字,如旧斜体数字一。
开始标点符号 :Ps 匹配开始标点符号,例如左方括号和左大括号。
结束标点符号 :Pe 匹配结束标点符号,例如右方括号和右大括号。
左引号 :Pi 匹配左双引号。
右引号 :Pf 匹配单引号和右双引号。
破折号 :Pd 匹配破折号标记。
连接符号 :Pc 匹配下划线标记。
其他标点符号 :Po 匹配逗号 (,)、?、"、!、@、#、%、&、*、\、冒号 (:)、分号 (;)、' 和 /。
空白分隔符 :Zs 匹配空白。
行分隔符 :Zl 匹配 Unicode 字符 U+2028。
段落分隔符 :Zp 匹配 Unicode 字符 U+2029。
无间隔标记 :Mn 匹配无间隔标记。
组合标记 :Mc 匹配组合标记。
封闭标记 :Me 匹配封闭标记。
数学符号 :Sm 匹配 +、=、~、| 、< 和 >。
货币符号 :Sc 匹配 $ 和其他货币符号。
修饰符号 :Sk 匹配修饰符号,如抑扬音、抑音符号和长音符号。
其他符号 :So 匹配其他符号,如版权符号、段落标记和度数符号。
其他控制 :Cc 匹配行尾。
其他格式 :Cf 格式化控制字符,例如双向控制字符。
代理项 :Cs 匹配代理项对的一半。
其他私用 :Co 匹配私用区域的任何字符。
其他未分配的字符 :Cn 匹配未映射到 Unicode 字符的字符。

除标准 Unicode 字符属性外,还可以指定下列附加属性。可将这些属性指定为字符集的一部分。

表达式 语法 说明
Alpha :Al 匹配任何一个字符。例如,:Alhe 匹配“The”、“then”、“reached”等单词。
数字 :Nu 匹配任何一个数或数字。
标点符号 :Pu 匹配任何一个标点符号,如 ?、@、' 等等。
空白 :Wh 匹配所有类型的空格,包括印刷和表意文字的空格。
Bidi :Bi 匹配诸如阿拉伯文和希伯来文这类从右向左书写的字符。
朝鲜文 :Ha 匹配朝鲜文和组合朝鲜文字母。
平假名 :Hi 匹配平假名字符。
片假名 :Ka 匹配片假名字符。
表意文字/汉字/日文汉字 :Id 匹配表意文字字符,如汉字和日文汉字

posted @ 2009-08-07 17:15 键盘的咏叹调 阅读(482) | 评论 (0)编辑 收藏

2009年3月12日 #

KMP算法

     摘要:    传统的字符串匹配算法中,为了在一段字符串中查找模式字符串的话需要使用2个循环嵌套起来,例如: int i=0;while(i< str.length()-parten.length()){    int j=0;    while(parte...  阅读全文

posted @ 2009-03-12 22:46 键盘的咏叹调 阅读(364) | 评论 (0)编辑 收藏

2009年2月18日 #

[zz]c++的一些资源

  4,工具

  C++的辅助工具繁多,我们分门别类的为大家作介绍:

  4.1 文档类

  (1) Doxygen

  参考站点:http://www.doxygen.org/

  Doxygen是一种适合C风格语言(如C++、C、IDL、Java甚至包括C#和PHP)的、
开放源码的、基于命令行的文档产生器。

  (2) C++2HTML

  参考站点:http://www.bedaux.net/cpp2html/

  把C++代码变成语法高亮的HTML

  (3) CodeColorizer

  参考站点:http://www.chami.com/colorizer/

  它能把好几种语言的源代码着色为HTML

  (4) Doc-O-Matic

  参考站点:http://www.doc-o-matic.com/

  Doc-O_Matic为你的C/C++,C++.net,Delphi/Pascal, VB.NET,C#和Java程序
或者组件产生准确的文档。Doc-O-Matic使用源代码中的符号和注释以及外部的文档
文件创建与流行的文档样式一致的文档。

  (5) DocVizor

  参考站点:http://www.ucancode.net/Products/DocBuilder/Features.htm

  DocVizor满足了面向对象软件开发者的基本要求——它让我们能够看到C++工程
中的类层次结构。DocVizor快速地产生完整可供打印的类层次结构图,包括从第三
方库中来的那些类,除此之外DocVizor还能从类信息中产生HTML文件。

  (6) SourcePublisher C++

  参考站点:http://www.scitools.com/sourcepublisher_c.html

  给源代码产生提供快速直观的HTML报表,包括代码,类层次结构,调用和被调
用树,包含和被包含树。支持多种操作系统。

  (7) Understand

  参考站点:http://www.scitools.com/ucpp.html

  分析任何规模的C或者C++工程,帮助我们更好的理解以及编写文档。

  4.2 代码类

  (1) CC-Rider

  参考站点:http://www.cc-rider.com/

  CC-Rider是用于C/C++程序强大的代码可视化工具,通过交互式浏览、编辑及自
动文件来促进程序的维持和发展。

  (2) CodeInspect

  参考站点:http://www.yokasoft.com/

  一种新的C/C++代码分析工具。它检查我们的源代码找出非标准的,可能的,以
及普通的错误代码。

  (3) CodeWizard

  参考站点:http://www.parasoft.com/

  先进的C/C++源代码分析工具,使用超过500个编码规范自动化地标明危险的,
但是编译器不能检查到的代码结构。

  (4) C++ Validation Test Suites

  参考站点:http://www.plumhall.com/suites.html

  一组用于测试编译器和库对于标准吻合程度的代码库。

  (5) CppRefactory

  参考站点:http://cpptool.sourceforge.net/

  CPPRefactory是一个使得开发者能够重构他们的C++代码的程序。目的是使得C
++代码的重构能够尽可能的有效率和简单。

  (6) Lzz

  参考站点:http://www.lazycplusplus.com/

  Lzz是一个自动化许多C++编程中的体力活的工具。它能够节省我们许多事件并
且使得编码更加有乐趣。给出一系列的声明,Lzz会给我们创建头文件和源文件。

  (7) QA C++ Generation 2000

  参考站点:http://www.programmingresearch.com/solutions/qacpp.htm

  它关注面向对象的C++源代码,对有关于设计,效率,可靠性,可维护性的部分
提出警告信息。

  (8) s-mail project - Java to C++DOL

  参考站点:http://sadlocha.strefa.pl/s-mail/ja2dol.html

  把Java源代码翻译为相应的C++源代码的命令行工具。

  (9) SNIP from Cleanscape Software International

  参考站点:http://www.cleanscape.net/stdprod/snip/index.html

  一个填平编码和设计之间沟壑的易于使用的C++开发工具,节省大量编辑和调试
的事件,它还使得开发者能够指定设计模式作为对象模型,自动从对象模型中产生
C++的类。

  (10) SourceStyler C++

  参考站点:http://www.ochresoftware.com/

  对C/C++源代码提供完整的格式化和排版控制的工具。提供多于75个的格式化选
项以及完全支持ANSI C++。

  4.3 编译类

  (1) Compilercache

  参考站点:http://www.erikyyy.de/compilercache/

  Compilercache是一个对你的C和C++编译器的封装脚本。每次我们进行编译,封
装脚本,把编译的结果放入缓存,一旦编译相同的东西,结果将从缓存中取出而不
是再次编译。

  (2) Ccache

  参考站点:http://ccache.samba.org/

  Ccache是一个编译器缓存。它使用起来就像C/C++编译器的缓存预处理器,编译
速度通常能提高普通编译过程的5~10倍。

  (3) Cmm (C++ with MultiMethods)

  参考站点:http://www.op59.net/cmm/cmm-0.28/users.html

  这是一种C++语言的扩展。读入Cmm源代码输出C++的源代码,功能是对C++语言
添加了对multimethod的支持。

  (4) The Frost Project

  参考站点:http://frost.flewid.de/

  Forst使得你能够在C++程序中像原生的C++特性一样使用multimethod以及虚函
数参数。它是一个编译器的外壳。

  4.4 测试和调试类

  (1) CPPUnit

  CppUnit 是个基于 LGPL 的开源项目,最初版本移植自 JUnit,是一个非常优
秀的开源测试框架。CppUnit 和 JUnit 一样主要思想来源于极限编程。主要功能就
是对单元测试进行管理,并可进行自动化测试。

  (2) C++Test

  参考站点:http://www.parasoft.com/

  C++ Test是一个单元测试工具,它自动化了C和C++类,函数或者组件的测试。


  (3) Cantata++

  参考站点:http://www.iplbath.com/products/tools/pt400.shtml

  设计的目的是为了满足在合理的经济开销下使用这个工具可以让开发工程师开
展单元测试和集成测试的需求.

  (4) Purify

  参考站点:http://www-900.ibm.com/cn/software/rational/products/purif
yplus/index.shtml

  IBM Rational PurifyPlus是一套完整的运行时分析工具,旨在提高应用程序的
可靠性和性能。PurifyPlus将内存错误和泄漏检测、应用程序性能描述、代码覆盖
分析等功能组合在一个单一、完整的工具包中。

  (5) BoundsChecker

  BoundsChecker是一个C++运行时错误检测和调试工具。它通过在Visual Studi
o内自动化调试过程加速开发并且缩短上市的周期。BoundsChecker提供清楚,详细
的程序错误分析,许多是对C++独有的并且在static,stack和heap内存中检测和诊
断错误,以及发现内存和资源的泄漏。  (6) Insure++

  参考站点:http://www.parasoft.com/

  一个自动化的运行时程序测试工具,检查难以察觉的错误,如内存覆盖,内存泄
漏,内存分配错误,变量初始化错误,变量定义冲突,指针错误,库错误,逻辑错
误和算法错误等。

  (7) GlowCode

  参考站点:http://www.glowcode.com/

  GlowCode包括内存泄漏检查,code profiler,函数调用跟踪等功能。给C++开
发者提供完整的错误诊断,和运行时性能分析工具包。

  (8) Stack Spy

  参考站点:http://www.imperioustech.com/

  它能捕捉stack corruption, stack over run, stack overflow等有关栈的错
误。

------------------------------------------------------------------------

5,库

 

  在C++中,库的地位是非常高的。C++之父 Bjarne Stroustrup先生多次表示了
设计库来扩充功能要好过设计更多的语法的言论。现实中,C++的库门类繁多,解决
的问题也是极其广泛,库从轻量级到重量级的都有。不少都是让人眼界大开,亦或
是望而生叹的思维杰作。由于库的数量非常庞大,而且限于笔者水平,其中很多并
不了解。所以文中所提的一些库都是比较著名的大型库。

  5.1 标准库

  标准库中提供了C++程序的基本设施。虽然C++标准库随着C++标准折腾了许多年
,直到标准的出台才正式定型,但是在标准库的实现上却很令人欣慰得看到多种实
现,并且已被实践证明为有工业级别强度的佳作。

  (1) Dinkumware C++ Library

  参考站点:http://www.dinkumware.com/

  P.J. Plauger编写的高品质的标准库。P.J. Plauger博士是Dr. Dobb's程序设
计杰出奖的获得者。其编写的库长期被Microsoft采用,并且最近Borland也取得了
其OEM的license,在其C/C++的产品中采用Dinkumware的库。

  (2) RogueWave Standard C++ Library

  参考站点:http://www.roguewave.com/

  这个库在Borland C++ Builder的早期版本中曾经被采用,后来被其他的库给替
换了。笔者不推荐使用。

  (3) SGI STL

  参考站点:http://www.roguewave.com/

  SGI公司的C++标准模版库。

  (4) STLport

  参考站点:http://www.stlport.org/

  SGI STL库的跨平台可移植版本。

  5.2 “准”标准库 - Boost

  参考站点:http://www.boost.org/

  国内镜像:http://www.c-view.org/tech/lib/boost/index.htm

  Boost库是一个经过千锤百炼、可移植、提供源代码的C++库,作为标准库的后
备,是C++标准化进程的发动机之一。 Boost库由C++标准委员会库工作组成员发起
,在C++社区中影响甚大,其成员已近2000人。 Boost库为我们带来了最新、最酷、
最实用的技术,是不折不扣的“准”标准库。

  Boost中比较有名气的有这么几个库:

  Regex

  正则表达式库

  Spirit

  LL parser framework,用C++代码直接表达EBNF

  Graph

  图组件和算法

  Lambda

  在调用的地方定义短小匿名的函数对象,很实用的functional功能

  concept check

  检查泛型编程中的concept


  Mpl

  用模板实现的元编程框架


  Thread

  可移植的C++多线程库


  Python

  把C++类和函数映射到Python之中

  Pool

  内存池管理


  smart_ptr

  5个智能指针,学习智能指针必读,一份不错的参考是来自CUJ的文章:

  Smart Pointers in Boost,哦,这篇文章可以查到,CUJ是提供在线浏览的。
中文版见笔者在《Dr. Dobb's Journal软件研发杂志》第7辑上的译文。

  Boost总体来说是实用价值很高,质量很高的库。并且由于其对跨平台的强调,
对标准C++的强调,是编写平台无关,现代C++的开发者必备的工具。但是Boost中也
有很多是实验性质的东西,在实际的开发中实用需要谨慎。并且很多Boost中的库功
能堪称对语言功能的扩展,其构造用尽精巧的手法,不要贸然的花费时间研读。Bo
ost另外一面,比如Graph这样的库则是具有工业强度,结构良好,非常值得研读的
精品代码,并且也可以放心的在产品代码中多多利用。

  5.3 GUI

  在众多C++的库中,GUI部分的库算是比较繁荣,也比较引人注目的。在实际开
发中,GUI库的选择也是非常重要的一件事情,下面我们综述一下可选择的GUI库,
各自的特点以及相关工具的支持。

  (1) MFC

  大名鼎鼎的微软基础类库(Microsoft Foundation Class)。大凡学过VC++的
人都应该知道这个库。虽然从技术角度讲,MFC是不大漂亮的,但是它构建于Windo
ws API 之上,能够使程序员的工作更容易,编程效率高,减少了大量在建立 Windo
ws 程序时必须编写的代码,同时它还提供了所有一般 C++ 编程的优点,例如继承
和封装。MFC 编写的程序在各个版本的Windows操作系统上是可移植的,例如,在
Windows 3.1下编写的代码可以很容易地移植到 Windows NT 或 Windows 95 上。但
是在最近发展以及官方支持上日渐势微。

  (2) QT

  参考网站:http://www.trolltech.com/

  Qt是Trolltech公司的一个多平台的C++图形用户界面应用程序框架。它提供给
应用程序开发者建立艺术级的图形用户界面所需的所用功能。Qt是完全面向对象的
很容易扩展,并且允许真正地组件编程。自从1996年早些时候,Qt进入商业领域,
它已经成为全世界范围内数千种成功的应用程序的基础。Qt也是流行的Linux桌面环
境KDE 的基础,同时它还支持Windows、Macintosh、Unix/X11等多种平台。

  (3) WxWindows

  参考网站:http://www.wxwindows.org/

  跨平台的GUI库。因为其类层次极像MFC,所以有文章介绍从MFC到WxWindows的
代码移植以实现跨平台的功能。通过多年的开发也是一个日趋完善的GUI库,支持同
样不弱于前面两个库。并且是完全开放源代码的。新近的C++ Builder X的GUI设计
器就是基于这个库的。

  (4) Fox

  参考网站:http://www.fox-toolkit.org/

  开放源代码的GUI库。作者从自己亲身的开发经验中得出了一个理想的GUI库应
该是什么样子的感受出发,从而开始了对这个库的开发。有兴趣的可以尝试一下。


  (5) WTL

  基于ATL的一个库。因为使用了大量ATL的轻量级手法,模板等技术,在代码尺
寸,以及速度优化方面做得非常到位。主要面向的使用群体是开发COM轻量级供网络
下载的可视化控件的开发者。

  (6) GTK

  参考网站:http://gtkmm.sourceforge.net/

  GTK是一个大名鼎鼎的C的开源GUI库。在Linux世界中有Gnome这样的杀手应用。
而GTK就是这个库的C++封装版本。

  5.4 网络通信

  (1) ACE

  参考网站:http://www.cs.wustl.edu/~schmidt/ACE.html

  C++库的代表,超重量级的网络通信开发框架。ACE自适配通信环境(Adaptive
Communication Environment)是可以自由使用、开放源代码的面向对象框架,在
其中实现了许多用于并发通信软件的核心模式。ACE提供了一组丰富的可复用C++包
装外观(Wrapper Facade)和框架组件,可跨越多种平台完成通用的通信软件任务
,其中包括:事件多路分离和事件处理器分派、信号处理、服务初始化、进程间通
信、共享内存管理、消息路由、分布式服务动态(重)配置、并发执行和同步,等
等。

  (2) StreamModule

  参考网站:http://www.omnifarious.org/StrMod/

  设计用于简化编写分布式程序的库。尝试着使得编写处理异步行为的程序更容
易,而不是用同步的外壳包起异步的本质。

  (3) SimpleSocket

  参考网站:http://home.hetnet.nl/~lcbokkers/simsock.htm

  这个类库让编写基于socket的客户/服务器程序更加容易。

  (4) A Stream Socket API for C++

  参考网站:http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.h
tml

  又一个对Socket的封装库。

  5.5 XML

  (1) Xerces

  参考网站:http://xml.apache.org/xerces-c/

  Xerces-C++ 是一个非常健壮的XML解析器,它提供了验证,以及SAX和DOM API
。XML验证在文档类型定义(Document Type Definition,DTD)方面有很好的支持,
并且在2001年12月增加了支持W3C XML Schema 的基本完整的开放标准。

  (2) XMLBooster

  参考网站:http://www.xmlbooster.com/

  这个库通过产生特制的parser的办法极大的提高了XML解析的速度,并且能够产
生相应的GUI程序来修改这个parser。在DOM和SAX两大主流XML解析办法之外提供了
另外一个可行的解决方案。

  (3) Pull Parser

  参考网站:http://www.extreme.indiana.edu/xgws/xsoap/xpp/

  这个库采用pull方法的parser。在每个SAX的parser底层都有一个pull的parse
r,这个xpp把这层暴露出来直接给大家使用。在要充分考虑速度的时候值得尝试。


  (4) Xalan

  参考网站:http://xml.apache.org/xalan-c/

  Xalan是一个用于把XML文档转换为HTML,纯文本或者其他XML类型文档的XSLT处
理器。

  (5) CMarkup

  参考网站:http://www.firstobject.com/xml.htm

  这是一种使用EDOM的XML解析器。在很多思路上面非常灵活实用。值得大家在D
OM和SAX之外寻求一点灵感。

  (6) libxml++

  http://libxmlplusplus.sourceforge.net/

  libxml++是对著名的libxml XML解析器的C++封装版本

  5.6 科学计算

  (1) Blitz++

  参考网站:http://www.oonumerics.org/blitz/

  Blitz++ 是一个高效率的数值计算函数库,它的设计目的是希望建立一套既具
像C++ 一样方便,同时又比Fortran速度更快的数值计算环境。通常,用C++所写出
的数值程序,比 Fortran慢20%左右,因此Blitz++正是要改掉这个缺点。方法是利
用C++的template技术,程序执行甚至可以比Fortran更快。Blitz++目前仍在发展中
,对于常见的SVD,FFTs,QMRES等常见的线性代数方法并不提供,不过使用者可以
很容易地利用Blitz++所提供的函数来构建。

  (2) POOMA

  参考网站:http://www.codesourcery.com/pooma/pooma

  POOMA是一个免费的高性能的C++库,用于处理并行式科学计算。POOMA的面向对
象设计方便了快速的程序开发,对并行机器进行了优化以达到最高的效率,方便在
工业和研究环境中使用。

  (3) MTL

  参考网站:http://www.osl.iu.edu/research/mtl/

  Matrix Template Library(MTL)是一个高性能的泛型组件库,提供了各种格式
矩阵的大量线性代数方面的功能。在某些应用使用高性能编译器的情况下,比如In
tel的编译器,从产生的汇编代码可以看出其与手写几乎没有两样的效能。

  (4) CGAL

  参考网站:http://www.cgal.org/

  Computational Geometry Algorithms Library的目的是把在计算几何方面的大
部分重要的解决方案和方法以C++库的形式提供给工业和学术界的用户。

  5.7 游戏开发

  (1) Audio/Video 3D C++ Programming Library

  参考网站:http://www.galacticasoftware.com/products/av/

  AV3D是一个跨平台,高性能的C++库。主要的特性是提供3D图形,声效支持(S
B,以及S3M),控制接口(键盘,鼠标和遥感),XMS。

  (2) KlayGE

  参考网站:http://home.g365.net/enginedev/

  国内游戏开发高手自己用C++开发的游戏引擎。KlayGE是一个开放源代码、跨平
台的游戏引擎,并使用Python作脚本语言。KlayGE在LGPL协议下发行。感谢龚敏敏
先生为中国游戏开发事业所做出的贡献。

  (3) OGRE

  参考网站:http://www.ogre3d.org/

  OGRE(面向对象的图形渲染引擎)是用C++开发的,使用灵活的面向对象3D引擎
。它的目的是让开发者能更方便和直接地开发基于3D硬件设备的应用程序或游戏。
引擎中的类库对更底层的系统库(如:Direct3D和OpenGL)的全部使用细节进行了
抽象,并提供了基于现实世界对象的接口和其它类。

  5.8 线程

  (1) C++ Threads

  参考网站:http://threads.sourceforge.net/

  这个库的目标是给程序员提供易于使用的类,这些类被继承以提供在Linux环境
中很难看到的大量的线程方面的功能。

  (2) ZThreads

  参考网站:http://zthread.sourceforge.net/

  一个先进的面向对象,跨平台的C++线程和同步库。

  5.9 序列化

  (1) s11n

  参考网站:http://s11n.net/

  一个基于STL的C++库,用于序列化POD,STL容器以及用户定义的类型。

  (2) Simple XML Persistence Library

  参考网站:http://sxp.sourceforge.net/

  这是一个把对象序列化为XML的轻量级的C++库。

  5.10 字符串

  (1) C++ Str Library

  参考网站:http://www.utilitycode.com/str/

  操作字符串和字符的库,支持Windows和支持gcc的多种平台。提供高度优化的
代码,并且支持多线程环境和Unicode,同时还有正则表达式的支持。

  (2) Common Text Transformation Library

  参考网站:http://cttl.sourceforge.net/

  这是一个解析和修改STL字符串的库。CTTL substring类可以用来比较,插入,
替换以及用EBNF的语法进行解析。

  (3) GRETA

  参考网站:http://research.microsoft.com/projects/greta/

  这是由微软研究院的研究人员开发的处理正则表达式的库。在小型匹配的情况
下有非常优秀的表现。

  5.11 综合

  (1) P::Classes

  参考网站:http://pclasses.com/

  一个高度可移植的C++应用程序框架。当前关注类型和线程安全的signal/slot
机制,i/o系统包括基于插件的网络协议透明的i/o架构,基于插件的应用程序消息
日志框架,访问sql数据库的类等等。

  (2) ACDK - Artefaktur Component Development Kit

  参考网站:http://acdk.sourceforge.net/

  这是一个平台无关的C++组件框架,类似于Java或者.NET中的框架(反射机制,
线程,Unicode,废料收集,I/O,网络,实用工具,XML,等等),以及对Java, P
erl, Python, TCL, Lisp, COM 和 CORBA的集成。

  (3) dlib C++ library

  参考网站:http://www.cis.ohio-state.edu/~kingd/dlib/

  各种各样的类的一个综合。大整数,Socket,线程,GUI,容器类,以及浏览目
录的API等等。

  (4) Chilkat C++ Libraries

  参考网站:http://www.chilkatsoft.com/cpp_libraries.asp

  这是提供zip,e-mail,编码,S/MIME,XML等方面的库。

  (5) C++ Portable Types Library (PTypes)

  参考网站:http://www.melikyan.com/ptypes/

  这是STL的比较简单的替代品,以及可移植的多线程和网络库。

  (6) LFC

  参考网站:http://lfc.sourceforge.net/

  哦,这又是一个尝试提供一切的C++库

  5.12 其他库

  (1) Loki

  参考网站:http://www.moderncppdesign.com/

  哦,你可能抱怨我早该和Boost一起介绍它,一个实验性质的库。作者在loki中
把C++模板的功能发挥到了极致。并且尝试把类似设计模式这样思想层面的东西通过
库来提供。同时还提供了智能指针这样比较实用的功能。

  (2) ATL

  ATL(Active Template Library)

  是一组小巧、高效、灵活的类,这些类为创建可互操作的COM组件提供了基本的
设施。

  (3) FC++: The Functional C++ Library

  这个库提供了一些函数式语言中才有的要素。属于用库来扩充语言的一个代表
作。如果想要在OOP之外寻找另一分的乐趣,可以去看看函数式程序设计的世界。大
师Peter Norvig在 “Teach Yourself Programming in Ten Years”一文中就将函
数式语言列为至少应当学习的6类编程语言之一。

  (4) FACT!

  参考网站:http://www.kfa-juelich.de/zam/FACT/start/index.html

  另外一个实现函数式语言特性的库

  (5) Crypto++

  提供处理密码,消息验证,单向hash,公匙加密系统等功能的免费库。

  还有很多非常激动人心或者是极其实用的C++库,限于我们的水平以及文章的篇
幅不能包括进来。在对于这些已经包含近来的库的介绍中,由于并不是每一个我们
都使用过,所以难免有偏颇之处,请读者见谅。

posted @ 2009-02-18 14:44 键盘的咏叹调 阅读(633) | 评论 (1)编辑 收藏

2009年2月3日 #

【zz】使用CRT调试内存分配堆来找出未释放的内存空间

     摘要:    原地址:http://blog.csdn.net/Donjuan/archive/2009/02/02/3859154.aspx   忘记释放已经分配的内存是一种常见的编程错误,当然我指的是在C++编程当中,例如下面的代码里面就存在一个忘记释放内存的编程错误。我个人觉得忘记释放内存的编程错误是不可避免的,毕竟程序员都是人,困了,心情...  阅读全文

posted @ 2009-02-03 11:59 键盘的咏叹调 阅读(391) | 评论 (0)编辑 收藏

2009年1月25日 #

[zz]漫谈malloc的实现

         malloc()是C语言中动态存储管理的一组标准库函数之一。其作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。

   动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不像数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。本文简单介绍动态内存分配函数malloc()及几种实现方法。

   1. 简介

  malloc()是C语言中动态存储管理的一组标准库函数之一。其作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。还有一点必须注意的是,当函数未能成功分配存储空间(如内存不足)就会返回一个NULL指针。所以在调用该函数时应该检测返回值是否为NULL并执行相应的操作。

   2. 函数说明

  C语言的动态存储管理由一组标准库函数实现,其原型在标准文件<stdlib.h>里描述,需要用这些功能时应包含这个文件。与动态存储分配有关的函数共有四个,其中就包括存储分配函数malloc()。函数原型是:void *malloc (size_t n);这里的size_t是标准库里定义的一个类型,它是一个无符号整型。这个整型能够满足所有对存储块大小描述的需要,具体相当于哪个整型由具体的C系统确定。malloc的返回值为(void *)类型(这是通用指针的一个重要用途),它分配一片能存放大小为n的数据的存储块,返回对应的指针值;如果不能满足申请(找不到能满足要求的存储块)就返回NULL。在使用时,应该把malloc的返回值转换到特定指针类型,赋给一个指针。

    注意,虽然这里的存储块是通过动态分配得到的,但是它的大小也是确定的,同样不允许越界使用。例如上面程序段分配的块里能存n个双精度数据,随后的使用就必须在这个范围内进行。越界使用动态分配的存储块,尤其是越界赋值,可能引起非常严重的后果,通常会破坏程序的运行系统,可能造成本程序或者整个计算机系统垮台。

  下例是一个动态分配的例子:
#include <stdlib.h>

main()
{
 int count,*array; /*count是一个计数器,array是一个整型指针,也可以理解为指向一个整型数组的首地址*/
 if((array(int *) malloc (10*sizeof(int)))==NULL)
 {
  printf("不能成功分配存储空间。");
  exit(1);
 }
 for (count=0;count〈10;count++) /*给数组赋值*/
  array[count]=count;
 for(count=0;count〈10;count++) /*打印数组元素*/
  printf("%2d",array[count]);
}

  上例中动态分配了10个整型存储区域,然后进行赋值并打印。例中if((array(int *) malloc (10*sizeof(int)))==NULL)语句可以分为以下几步:
  1)分配10个整型的连续存储空间,并返回一个指向其起始地址的整型指针
  2)把此整型指针地址赋给array
  3)检测返回值是否为NULL

   3. malloc()工作机制

  malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。

   4. malloc()在操作系统中的实现

  在 C 程序中,多次使用malloc () 和 free()。不过,您可能没有用一些时间去思考它们在您的操作系统中是如何实现的。本节将向您展示 malloc 和 free 的一个最简化实现的代码,来帮助说明管理内存时都涉及到了哪些事情。

  在大部分操作系统中,内存分配由以下两个简单的函数来处理:

  void *malloc (long numbytes):该函数负责分配 numbytes 大小的内存,并返回指向第一个字节的指针。

  void free(void *firstbyte):如果给定一个由先前的 malloc 返回的指针,那么该函数会将分配的空间归还给进程的“空闲空间”。

  malloc_init 将是初始化内存分配程序的函数。它要完成以下三件事:将分配程序标识为已经初始化,找到系统中最后一个有效内存地址,然后建立起指向我们管理的内存的指针。这三个变量都是全局变量:

  清单 1. 我们的简单分配程序的全局变量

        int has_initialized = 0;
        void *managed_memory_start;
        void *last_valid_address;

  如前所述,被映射的内存的边界(最后一个有效地址)常被称为系统中断点或者 当前中断点。在很多 UNIX? 系统中,为了指出当前系统中断点,必须使用 sbrk(0) 函数。 sbrk 根据参数中给出的字节数移动当前系统中断点,然后返回新的系统中断点。使用参数 0 只是返回当前中断点。这里是我们的 malloc 初始化代码,它将找到当前中断点并初始化我们的变量:

  清单 2. 分配程序初始化函数
/* Include the sbrk function */
 
#include
void malloc_init()
{
/* grab the last valid address from the OS */
last_valid_address = sbrk(0);
/* we don't have any memory to manage yet, so
 *just set the beginning to be last_valid_address
 */
managed_memory_start = last_valid_address;
/* Okay, we're initialized and ready to go */
 has_initialized = 1;
}

  现在,为了完全地管理内存,我们需要能够追踪要分配和回收哪些内存。在对内存块进行了 free 调用之后,我们需要做的是诸如将它们标记为未被使用的等事情,并且,在调用 malloc 时,我们要能够定位未被使用的内存块。因此, malloc 返回的每块内存的起始处首先要有这个结构:

  清单 3. 内存控制块结构定义
struct mem_control_block {
int is_available;
int size;
};
   

   现在,您可能会认为当程序调用 malloc 时这会引发问题 —— 它们如何知道这个结构?答案是它们不必知道;在返回指针之前,我们会将其移动到这个结构之后,把它隐藏起来。这使得返回的指针指向没有用于任何其他用途的内存。那样,从调用程序的角度来看,它们所得到的全部是空闲的、开放的内存。然后,当通过 free() 将该指针传递回来时,我们只需要倒退几个内存字节就可以再次找到这个结构。

  在讨论分配内存之前,我们将先讨论释放,因为它更简单。为了释放内存,我们必须要做的惟一一件事情就是,获得我们给出的指针,回退 sizeof(struct mem_control_block) 个字节,并将其标记为可用的。这里是对应的代码:

  清单 4. 解除分配函数
void free(void *firstbyte) {
struct mem_control_block *mcb;
/* Backup from the given pointer to find the
 * mem_control_block
 */
mcb = firstbyte - sizeof(struct mem_control_block);
/* Mark the block as being available */
mcb->is_available = 1;
/* That's It!  We're done. */
return;
}

  如您所见,在这个分配程序中,内存的释放使用了一个非常简单的机制,在固定时间内完成内存释放。分配内存稍微困难一些。以下是该算法的略述:

  清单 5. 主分配程序的伪代码
1. If our allocator has not been initialized, initialize it.
2. Add sizeof(struct mem_control_block) to the size requested.
3. start at managed_memory_start.
4. Are we at last_valid address?
5. If we are:
   A. We didn't find any existing space that was large enough
      -- ask the operating system for more and return that.
6. Otherwise:
   A. Is the current space available (check is_available from
      the mem_control_block)?
   B. If it is:
      i)   Is it large enough (check "size" from the
           mem_control_block)?
      ii)  If so:
           a. Mark it as unavailable
           b. Move past mem_control_block and return the
              pointer
      iii) Otherwise:
           a. Move forward "size" bytes
           b. Go back go step 4
   C. Otherwise:
      i)   Move forward "size" bytes
      ii)  Go back to step 4

  我们主要使用连接的指针遍历内存来寻找开放的内存块。这里是代码:

  清单 6. 主分配程序
void *malloc(long numbytes) {
/* Holds where we are looking in memory */
void *current_location;
/* This is the same as current_location, but cast to a
 * memory_control_block
 */
struct mem_control_block *current_location_mcb;
/* This is the memory location we will return.  It will
 * be set to 0 until we find something suitable
 */
void *memory_location;
/* Initialize if we haven't already done so */
if(! has_initialized) {
malloc_init();
}
/* The memory we search for has to include the memory
 * control block, but the users of malloc don't need
 * to know this, so we'll just add it in for them.
 */
numbytes = numbytes + sizeof(struct mem_control_block);
/* Set memory_location to 0 until we find a suitable
 * location
 */
memory_location = 0;
/* Begin searching at the start of managed memory */
current_location = managed_memory_start;
/* Keep going until we have searched all allocated space */
while(current_location != last_valid_address)
{
/* current_location and current_location_mcb point
 * to the same address.  However, current_location_mcb
 * is of the correct type, so we can use it as a struct.
 * current_location is a void pointer so we can use it
 * to calculate addresses.
 */
current_location_mcb =
(struct mem_control_block *)current_location;
if(current_location_mcb->is_available)
{
if(current_location_mcb->size >= numbytes)
{
/* Woohoo!  We've found an open,
 * appropriately-size location.
 */
/* It is no longer available */
current_location_mcb->is_available = 0;
/* We own it */
memory_location = current_location;
/* Leave the loop */
break;
}
}
/* If we made it here, it's because the Current memory
 * block not suitable; move to the next one
 */
current_location = current_location +
current_location_mcb->size;
}
/* If we still don't have a valid location, we'll
 * have to ask the operating system for more memory
 */
if(! memory_location)
{
/* Move the program break numbytes further */
sbrk(numbytes);
/* The new memory will be where the last valid
 * address left off
 */
memory_location = last_valid_address;
/* We'll move the last valid address forward
 * numbytes
 */
last_valid_address = last_valid_address + numbytes;
/* We need to initialize the mem_control_block */
current_location_mcb = memory_location;
current_location_mcb->is_available = 0;
current_location_mcb->size = numbytes;
}
/* Now, no matter what (well, except for error conditions),
 * memory_location has the address of the memory, including
 * the mem_control_block
 */
/* Move the pointer past the mem_control_block */
memory_location = memory_location + sizeof(struct mem_control_block);
/* Return the pointer */
return memory_location;
 }

  这就是我们的内存管理器。现在,我们只需要构建它,并在程序中使用它即可。
 

  5. malloc()的其他实现

  malloc() 的实现有很多,这些实现各有优点与缺点。在设计一个分配程序时,要面临许多需要折衷的选择,其中包括:

分配的速度。
回收的速度。
有线程的环境的行为。
内存将要被用光时的行为。
局部缓存。
簿记(Bookkeeping)内存开销。
虚拟内存环境中的行为。
小的或者大的对象。
实时保证。
每一个实现都有其自身的优缺点集合。在我们的简单的分配程序中,分配非常慢,而回收非常快。另外,由于它在使用虚拟内存系统方面较差,所以它最适于处理大的对象。

  还有其他许多分配程序可以使用。其中包括:

  Doug Lea Malloc:Doug Lea Malloc 实际上是完整的一组分配程序,其中包括 Doug Lea 的原始分配程序,GNU libc 分配程序和 ptmalloc。 Doug Lea 的分配程序有着与我们的版本非常类似的基本结构,但是它加入了索引,这使得搜索速度更快,并且可以将多个没有被使用的块组合为一个大的块。它还支持缓存,以便更快地再次使用最近释放的内存。 ptmalloc 是 Doug Lea Malloc 的一个扩展版本,支持多线程。在本文后面的 参考资料部分中,有一篇描述 Doug Lea 的 Malloc 实现的文章。

  BSD Malloc:BSD Malloc 是随 4.2 BSD 发行的实现,包含在 FreeBSD 之中,这个分配程序可以从预先确实大小的对象构成的池中分配对象。它有一些用于对象大小的 size 类,这些对象的大小为 2 的若干次幂减去某一常数。所以,如果您请求给定大小的一个对象,它就简单地分配一个与之匹配的 size 类。这样就提供了一个快速的实现,但是可能会浪费内存。在 参考资料部分中,有一篇描述该实现的文章。

  Hoard:编写 Hoard 的目标是使内存分配在多线程环境中进行得非常快。因此,它的构造以锁的使用为中心,从而使所有进程不必等待分配内存。它可以显著地加快那些进行很多分配和回收的多线程进程的速度。在 参考资料部分中,有一篇描述该实现的文章。
众多可用的分配程序中最有名的就是上述这些分配程序。如果您的程序有特别的分配需求,那么您可能更愿意编写一个定制的能匹配您的程序内存分配方式的分配程序。不过,如果不熟悉分配程序的设计,那么定制分配程序通常会带来比它们解决的问题更多的问题。

   6. 结束语

  前面已经提过,多次调用malloc()后空闲内存被切成很多的小内存片段,这就使得用户在申请内存使用时,由于找不到足够大的内存空间,malloc()需要进行内存整理,使得函数的性能越来越低。聪明的程序员通过总是分配大小为2的幂的内存块,而最大限度地降低潜在的malloc性能丧失。也就是说,所分配的内存块大小为4字节、8字节、16字节、18446744073709551616字节,等等。这样做最大限度地减少了进入空闲链的怪异片段(各种尺寸的小片段都有)的数量。尽管看起来这好像浪费了空间,但也容易看出浪费的空间永远不会超过50%。

   参考文献:

  [1]  Jonathan Bartlett,内存管理内幕. developerWorks 中国,2004年11月

posted @ 2009-01-25 13:13 键盘的咏叹调 阅读(640) | 评论 (0)编辑 收藏

2008年11月21日 #

切记,关于删除STL容器

  • 去除一个容器中有特定值的所有对象:

    如果容器是vector、string或deque,使用erase-remove惯用法。

    如果容器是list,使用list::remove。

    如果容器是标准关联容器,使用它的erase成员函数。

  • 去除一个容器中满足一个特定判定式的所有对象:

    如果容器是vector、string或deque,使用erase-remove_if惯用法。

    如果容器是list,使用list::remove_if。

    如果容器是标准关联容器,使用remove_copy_if和swap,或写一个循环来遍历容器元素,当你把迭代器传给erase时记得后置递增它。

  • 在循环内做某些事情(除了删除对象之外):

    如果容器是标准序列容器,写一个循环来遍历容器元素,每当调用erase时记得都用它的返回值更新你的迭代器。

    如果容器是标准关联容器,写一个循环来遍历容器元素,当你把迭代器传给erase时记得后置递增它。

posted @ 2008-11-21 10:40 键盘的咏叹调 阅读(247) | 评论 (0)编辑 收藏

2008年11月11日 #

【zz】dos重定向

dos重定向

使用命令重定向操作符

可以使用重定向操作符将命令输入和输出数据流从默认位置重定向到其他位置。输入或输出数据流的位置称为句柄。

下表将列出可用的句柄。

句柄 句柄的数字代号 描述

STDIN

0

键盘输入

STDOUT

1

输出到命令提示符窗口

STDERR

2

错误输出到命令提示符窗口

UNDEFINED

3-9

句柄由应用程序单独定义,它们是各个工具特有的

 

数 字 0 到 9 代表前 10 个句柄。可以使用命令 Cmd.exe 运行程序,并对该程序前 10 个句柄中的任何一个句柄进行重定向。要指定要用的句柄,请在重定向操作符之前键入该句柄的数字。如果未定义句柄,则默认的 < 重定向输入操作符是 0,而默认的 > 重定向输出操作符是 1。键入 < 或 > 操作符之后,必须指定数据的读写位置。可以指定文件名或其他现有的句柄。

要指定重定向到现有句柄,请使用与 (&) 字符,后面接要重定向的句柄号(即 &句柄号)。例如,下面的命令可以将句柄 2(即 STDERR)重定向到句柄 1(即 STDOUT):

2>&1

下表列出了可用于重定向输入和输出数据流的操作符。

重定向操作符 描述

>

将命令输出写入到文件或设备(如打印机),而不是命令提示符窗口或句柄。

<

从文件而不是从键盘或句柄读入命令输入。

>>

将命令输出添加到文件末尾而不删除文件中已有的信息。

>&

将一个句柄的输出写入到另一个句柄的输入中。

<&

从一个句柄读取输入并将其写入到另一个句柄输出中。

|

从一个命令中读取输出并将其写入另一个命令的输入中。也称作管道。

 

默认情况下,可以从键盘将命令输入(即 STDIN 句柄)发送到 Cmd.exe,然后由 Cmd.exe 将命令输出(即 STDOUT 句柄)发送到命令提示符窗口。

重定向输入 (<)

要通过键盘将输入重定向到文件或设备,请使用 < 操作符。例如,要从 File.txt 获取 sort 命令的输入,请键入:

sort<file.txt

File.txt 的内容将以字母顺序列表的方式显示在命令提示符窗口中。

< 操作符可以打开具有只读访问权限的指定文件名。因此,不能在使用该操作符时向文件中写入信息。例如,如果以 <&2 启动程序,则所有试图读取句柄 0 的操作都将失败,因为句柄 2 最初是以只写访问方式打开的。

注意

0 是 < 重定向输入操作符的默认句柄。

重定向输出 (>)

几乎所有的命令都将输出发送到命令提示符窗口。即使将输出发送到驱动器或打印机的命令也会在命令提示符窗口显示消息和提示。

要将输出从命令提示符窗口重定向到文件或设备,请使用 > 操作符。可以在许多命令中使用该操作符。例如,要将 dir 输出重定向到 Dirlist.txt,请键入:

dir>dirlist.txt

如果 Dirlist.txt 不存在,Cmd.exe 将创建该文件。如果 Dirlist.txt 存在,Cmd.exe 将使用 dir 命令的输出替换文件中的信息。

要运行 netsh routing dump 命令,然后将输出发送到 Route.cfg,请键入:

netsh routing dump>c:\route.cfg

> 操作符可以打开具有只写访问权限的指定文件。因此,不能使用该操作符读取文件。例如,如果使用重定向操作符 >&0 启动程序,则写入句柄 1 的所有尝试操作都将失败,因为句柄 0 最初是以只读访问方式打开的。

注意

1 是 > 重定向输出操作符的默认句柄。

复制句柄

重定向操作符 & 可以将输出或输入从一个指定句柄复制到另一个指定的句柄。例如,要将 dir 输出发送到 File.txt 并将错误输出发送到 File.txt,请键入:

dir>c:\file.txt 2>&1

复制句柄时,可以复制该句柄原状态的所有特性。例如,如果一个句柄具有只读访问的属性,则该句柄的所有副本都具有只读访问属性。不能将一个具有只读访问属性的句柄复制到另一个具有只写访问属性的句柄。

使用 & 操作符重定向输入和副本

要 将重定向输入操作符 (<) 与复制操作符 (&) 结合使用,指定的文件必须已经存在。如果输入文件存在,Cmd.exe 将以只读方式打开该文件,然后将文件包含的字符作为输入发送到此命令(如同从键盘输入一样)。如果指定了句柄,Cmd.exe 将指定的句柄复制到系统现有的句柄中。

例如,要以句柄 0 输入读取(即 STDIN)的方式打开 File.txt,请键入:

<file.txt

要打开 File.txt,并在内容排序后将输出发送到命令提示符窗口(即 STDOUT),请键入:

sort<file.txt

要查找 File.txt,然后将句柄 1(即 STDOUT)和句柄 2(即 STDERR)重定向到 Search.txt,请键入:

findfile file.txt>search.txt 2<&1

要以句柄 0 输入读取(即 STDIN)的方式复制用户定义的句柄 3,请键入:

<&3

使用 & 操作符重定向输出和复制

如果将输出重定向到文件且指定了现有的文件名,Cmd.exe 将以只写方式打开文件并覆盖该文件内容。如果指定了句柄,Cmd.exe 将文件复制到现有句柄中。

要将用户定义的句柄 3 复制到句柄 1,请键入:

>&3

要将包括句柄 2(即 STDERR)的所有输出从 ipconfig 命令重定向到句柄 1(即 STDOUT),然后将输出重定向到 Output.log,请键入:

ipconfig.exe>>output.log 2>&1

使用 >> 重定向操作符附加输出

要从命令中将输出添加到文件末尾而不丢失文件中已存在的任何信息,请使用两个连续的大于号(即 >>)。例如,使用下列命令可以将 dir 命令生成的目录列表附加到 Dirlist.txt 文件:

dir>>dirlist.txt

要将 netstat 命令的输出附加到 Tcpinfo.txt 的末尾,请键入:

netstat>>tcpinfo.txt

使用管道操作符 (|)

管道操作符 (|) 可以提取一个命令的输出(默认情况下是 STDOUT),然后将其定向到另一个命令的输入(默认情况下是 STDIN)中。例如,使用下面的命令可以对目录进行分类:

dir | sort

在本例中,将同时启动两个命令,但随后 sort 命令会暂停,直到它接收到 dir 命令的输出为止。sort 命令使用 dir 命令的输出作为输入,然后将输出发送到句柄 1(即 STDOUT)。

合并带重定向操作符的命令

通过合并带有其他命令和文件名的筛选器命令,可以创建自定义命令。例如,可以使用以下命令存储包含“LOG”字符串的文件名:

dir /b | find "log" loglist.txt

dir 命令的输出是通过 find 筛选器命令进行发送的。包含字符串“LOG”的文件名作为文件名列表(例如,NetshConfig.log、Logdat.svd 和 Mylog.bat)存储在文件 Loglist.txt 中。

要在相同命令中使用多个筛选器,请使用管道 (|) 分隔筛选器。例如,下面的命令将搜索 C 盘上的每个目录以查找包含“LOG”字符串的文件名,并且在命令提示符窗口中每次显示一屏:

dir c:\ /s /b | find "log" | more

利用管道 (|) 可以对 Cmd.exe 进行定向,使其通过 find 筛选器命令发送 dir 命令输出。find 命令只选择包含字符串“LOG”的文件名。more 命令可以显示 find 命令选择的文件名(在命令提示符窗口中每次显示一屏)。有关筛选器命令的详细信息,请参阅使用筛选器

posted @ 2008-11-11 15:52 键盘的咏叹调 阅读(919) | 评论 (0)编辑 收藏

仅列出标题  下一页