??xml version="1.0" encoding="utf-8" standalone="yes"?>国产69精品久久久久9999APGF ,久久精品国产亚洲麻豆,久久久久久久久久久精品尤物http://www.shnenglu.com/majianan/<br> <br> 人本是hQ不必刻意去做hQ世本是世,无须_ֿd世;自然的才是快乐的? <br><br> zh-cnThu, 08 May 2025 19:54:21 GMTThu, 08 May 2025 19:54:21 GMT60垃圾攉史Q{载)http://www.shnenglu.com/majianan/archive/2006/11/04/14666.html马嘉?/dc:creator>马嘉?/author>Sat, 04 Nov 2006 08:19:00 GMThttp://www.shnenglu.com/majianan/archive/2006/11/04/14666.htmlhttp://www.shnenglu.com/majianan/comments/14666.htmlhttp://www.shnenglu.com/majianan/archive/2006/11/04/14666.html#Feedback2http://www.shnenglu.com/majianan/comments/commentRss/14666.htmlhttp://www.shnenglu.com/majianan/services/trackbacks/14666.html                                            垃圾攉史Q{Q?/font>

                                                     王咏刚,2003q?2?br>

写作本文的初h惛_大家分n垃圾攉Q?Garbage Collection Q技术简单而有的发展双Ӏ动W之前,我站在窗边,望了望正在小区里装运垃圾的清zR。和生活中环卫工Z清运垃圾的工作相|软g开发里的垃圾收集其实就是一U自动打扫和清除内存垃圾的技术,它可以有效防范动态内存分配中可能发生的两个危险:因内存垃圾过多而引发的内存耗尽Q这和生zd圑֠塞排污管道的危险q没有什么本质的不同Q,以及不恰当的内存释放所造成的内存非法引用(q类g我们在生zM买到了一瓶已l过期三q的牛奶Q?

据历史学家们介绍Q四千多q前的古埃及人已l在城市里徏设了完善的排污和垃圾清运设施Q一千多q前的中国h更是修筑了当时世界上保洁能力最强的都市 ——长安。今天,当我们在软g开发中体验自动垃圾攉的便捷与舒适时Q我们至应当知道,q种拒绝杂ؕ、追求整z的“垃圾攉”_其实是hc自古以来就已经具备了的?

 

拓荒时代

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

国内的程序员大多是在 Java 语言中第一ơ感受到垃圾攉技术的巨大力的,许多Z因此?Java 和垃圾收集看成了密不可分的整体。但事实上,垃圾攉技术早?Java 语言问世?30 多年已l发展和成熟h了, Java 语言所做的不过是把q项奇的技术带Cq大E序员n边而已?

如果一定要为垃圾收集技术找一个孪生兄弟,那么Q?Lisp 语言才是当之无愧的h选?1960 q前后诞生于 MIT ?Lisp 语言是第一U高度依赖于动态内存分配技术的语言Q?Lisp 中几乎所有数据都?#8220;?#8221;的Ş式出玎ͼ?#8220;?#8221;所占用的空间则是在堆中动态分配得到的?Lisp 语言先天具有的动态内存管理特性要?Lisp 语言的设计者必解军_中每一个内存块的自动释N题(否则Q?Lisp E序员就必然被程序中不计其数?free ?delete 语句ҎQ,q直接导致了垃圾攉技术的诞生和发展——说句题外话Q上大学Ӟ一位老师曑֑诉我们, Lisp 是对C软g开发技术A献最大的语言。我当时对这一说法不以为然Q布满了圆括P看上dq宫一L Lisp 语言怎么能比 C 语言?Pascal 语言更伟大呢Q不q现在,当我知道垃圾攉技术、数据结构技术、h工智能技术、ƈ行处理技术、虚拟机技术、元数据技术以及程序员们耳熟能详的许多技术都h?Lisp 语言Ӟ我特别想向那位老师当面道歉Qƈ收回我当时的q稚x?

知道?Lisp 语言与垃圾收集的密切关系Q我们就不难理解Qؓ什么垃圾收集技术的两位先驱?J. McCarthy ?M. L. Minsky 同时也是 Lisp 语言发展史上的重要h物了?J. McCarthy ?Lisp 之父Q他在发?Lisp 语言的同时也W一ơ完整地描述了垃圾收集的法和实现方式; M. L. Minsky 则在发展 Lisp 语言的过E中成ؓ了今天好几种L垃圾攉法的奠Zh——和当时不少技术大师的l历怼Q?J. McCarthy ?M. L. Minsky 在许多不同的技术领域里都取得了令h艳M的成。也许,?1960 q代那个软g开发史上的拓荒时代里,思维敏捷、意志坚定的研究者更Ҏ成ؓ无所不能的西部硬汉吧?

在了解垃圾收集算法的h之前Q有必要先回一下内存分配的主要方式。我们知道,大多C的语言或运行环境都支持三种最基本的内存分配方式,它们分别是:

一、静态分配( Static Allocation Q:静态变量和全局变量的分配Ş式。我们可以把静态分配的内存看成是家里的耐用家具。通常Q它们无需释放和回Ӟ因ؓ没h会天天把大衣柜当作垃圾扔到窗外?

二、自动分配( Automatic Allocation Q:在栈中ؓ局部变量分配内存的Ҏ。栈中的内存可以随着代码块退出时的出栈操作被自动释放。这cM于到家中串门的访客,天色一晚就要各回各Ӟ除了个别不识时务者以外,我们一般没必要把客人捆在垃圾袋里扫地出门?

三、动态分配( Dynamic Allocation Q:在堆中动态分配内存空间以存储数据的方式。堆中的内存块好像我们日怋用的巾U,用过了就得扔到垃圄里,否则屋内׃满地D。像我这L懒h做梦都想有一台家用机器h跟在w边打扫卫生。在软g开发中Q如果你懒得释放内存Q那么你也需要一台类似的机器人——这其实是一个由特定法实现的垃圾收集器?

也就是说Q下面提到的所有垃圾收集算法都是在E序q行q程中收集ƈ清理废旧“巾U?#8221;的算法,它们的操作对象既不是静态变量,也不是局部变量,而是堆中所有已分配内存块?


 

引用计数Q?Reference Counting Q算?/font>

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

1960 q以前,Z胎中?Lisp 语言设计垃圾攉机制ӞW一个想到的法是引用计数算法。拿巾U的例子来说Q这U算法的原理大致可以描述为:

午餐ӞZ把脑子里H然跛_来的设计灉|C来,我从巾U袋中抽Z张餐巄Q打在上面dpȝ架构的蓝图。按?#8220;巾U怋用规U之引用计数?#8221;的要求,d之前Q我必须先在巾U的一角写上计数?1 Q以表示我在使用q张巾U。这Ӟ如果你也想看看我ȝ蓝图Q那你就要把巾U怸的计数值加 1 Q将它改?2 Q这表明目前?2 个h在同时用这张餐巄Q当Ӟ我是不会允许你用q张巾U来擦E涕的Q。你看完后,必须把计数值减 1 Q表明你对该巾U的使用已经l束。同P当我餐巄上的内容全部誊写到笔记本上之后,我也会自觉地把餐巄上的计数值减 1 。此Ӟ不出意外的话Q这张餐巄上的计数值应当是 0 Q它会被垃圾攉器——假N是一个专门负责打扫卫生的机器人——捡h扔到垃圾里Q因为垃圾收集器的惟一使命是扑ֈ所有计数gؓ 0 的餐巄q清理它们?

引用计数法的优点和~陷同样明显。这一法在执行垃圾收集Q务时速度较快Q但法对程序中每一ơ内存分配和指针操作提出了额外的要求Q增加或减少内存块的引用计数Q。更重要的是Q引用计数算法无法正释攑@环引用的内存块,ҎQ?D. Hillis 有一D风而精辟的Q?

一天,一个学生走?Moon 面前_“我知道如何设计一个更好的垃圾攉器了。我们必记录指向每个结点的指针数目?#8221; Moon 耐心地给q位学生讲了下面q个故事Q?#8220;一天,一个学生走?Moon 面前_‘我知道如何设计一个更好的垃圾攉器了……’”

D. Hillis 的故事和我们时候常说的“从前有山,׃有个庙,庙里有个老和?#8221;的故事有异曲同工之妙。这说明Q单是用引用计数算法还不以解军_圾收集中的所有问题。正因ؓ如此Q引用计数算法也常常被研I者们排除在狭义的垃圾攉法之外。当Ӟ作ؓ一U最单、最直观的解x案,引用计数法本nh其不可替代的优越性?1980 q代前后Q?D. P. Friedman Q?D. S. Wise Q?H. G. Baker {h对引用计数算法进行了数次改进Q这些改q得引用计数算法及其变U(如gq计数算法等Q在单的环境下,或是在一些综合了多种法的现代垃圾收集系l中仍然可以一展n手?

 

标记Q清除( Mark-Sweep Q算?/font>

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

W一U实用和完善的垃圾收集算法是 J. McCarthy {h?1960 q提出ƈ成功地应用于 Lisp 语言的标讎ͼ清除法。仍以餐巄ZQ标讎ͼ清除法的执行过E是q样的:

午餐q程中,厅里的所有h都根据自q需要取用餐巄。当垃圾攉机器人想攉废旧巾U的时候,它会让所有用的人先停下来,然后Q依ơ询问餐厅里的每一个hQ?#8220;你正在用巾U吗Q你用的是哪一张餐巄Q?#8221;机器人根据每个h的回{将Z正在使用的餐巄M记号。询问过E结束后Q机器h在餐厅里L所有散落在桌上且没有记号的餐巄Q这些显焉是用q的废旧巾U)Q把它们l统扔到垃圾里?

正如其名U所暗示的那P标记Q清除算法的执行q程分ؓ“标记”?#8220;清除”两大阶段。这U分步执行的思\奠定了现代垃圾收集算法的思想基础。与引用计数法不同的是Q标讎ͼ清除法不需要运行环境监每一ơ内存分配和指针操作Q而只要在“标记”阶段中跟t每一个指针变量的指向——用cM思\实现的垃圾收集器也常被后人统UCؓ跟踪攉器( Tracing Collector Q?

伴随着 Lisp 语言的成功,标记Q清除算法也在大多数早期?Lisp q行环境中大攑ּ彩。尽最初版本的标记Q清除算法在今天看来q存在效率不高(标记和清除是两个相当耗时的过E){诸多缺P但在后面的讨ZQ我们可以看刎ͼ几乎所有现代垃圾收集算法都是标讎ͼ清除思想的gl,仅此一点, J. McCarthy {h在垃圾收集技术方面的贡献׃毫不亚于他们?Lisp 语言上的成就了?

 

复制Q?Copying Q算?/font>

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

Z解决标记Q清除算法在垃圾攉效率斚w的缺P M. L. Minsky ?1963 q发表了著名的论?#8220;一U用双存储区的 Lisp 语言垃圾攉器( A LISP Garbage Collector Algorithm Using Serial Secondary Storage Q?#8221;?M. L. Minsky 在该论文中描q的法被h们称为复制算法,它也?M. L. Minsky 本h成功地引入到?Lisp 语言的一个实现版本中?

复制法别出心裁地将堆空间一分ؓ二,q用简单的复制操作来完成垃圾收集工作,q个思\相当有趣。借用巾U的比喻Q我们可以这L?M. L. Minsky 的复制算法:

厅被垃圾收集机器h分成南区和北Z个大完全相同的部分。午时Q所有h都先在南区用(因ؓI间有限Q用h数自然也减一半)Q用时可以随意使用巾U。当垃圾攉机器为有必要回收废旧巾U时Q它会要求所有用者以最快的速度从南{Ud北区Q同旉w携带自己正在用的巾U。等所有h都{Ud北区之后Q垃圾收集机器h只要单地把南Z所有散落的巾U扔q垃圄q完成d了。下一ơ垃圾收集的工作q程也大致类|惟一的不同只是h们的转移方向变成了从北区到南区。如此@环往复,每次垃圾攉都只需单地转移Q也是复制Q一ơ,垃圾攉速度无与伦比——当Ӟ对于用餐者往q奔波于南北两区之间的辛劻I垃圾攉机器人是决不会流露出丝毫怜悯的?

M. L. Minsky 的发明绝对算得上一U奇思妙惟뀂分区、复制的思\不仅大幅提高了垃圾收集的效率Q而且也将原本J纷复杂的内存分配算法变得前所未有地简明和DQ既然每ơ内存回攉是对整个半区的回Ӟ内存分配时也׃用考虑内存片{复杂情况,只要Ud堆顶指针Q按序分配内存可以了Q,q简直是个奇q!不过QQ何奇q的出现都有一定的代hQ在垃圾攉技术中Q复制算法提高效率的代h是h为地可用内存羃了一半。实话实_q个代h未免也太高了一些?

无论优缺点如何,复制法在实践中都获得了可以与标讎ͼ清除法相比拟的成功。除?M. L. Minsky 本h?Lisp 语言中的工作以外Q从 1960 q代末到 1970 q代初, R. R. Fenichel ?J. C. Yochelson {h也相l在 Lisp 语言的不同实C对复制算法进行了改进Q?S. Arnborg 更是成功地将复制法应用C Simula 语言中?

xQ垃圾收集技术的三大传统法——引用计数算法、标讎ͼ清除法和复制算法——都已在 1960 q前后相l问世,三种法各有所长,也都存在致命的缺陗从 1960 q代后期开始,研究者的主要_֊逐渐转向对这三种传统法q行改进或整合,以扬镉K短,适应E序设计语言和运行环境对垃圾攉的效率和实时性所提出的更高要求?

 

走向成熟

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

?1970 q代开始,随着U学研究和应用实늚不断深入Qh们逐渐意识刎ͼ一个理想的垃圾攉器不应在q行时导致应用程序的暂停Q不应额外占用大量的内存I间?CPU 资源Q而三U传l的垃圾攉法都无法满些要求。h们必L出更新的法或思\Q以解决实践中碰到的诸多N。当Ӟ研究者的努力目标包括Q?

W一Q提高垃圾收集的效率。用标讎ͼ清除法的垃圾收集器在工作时要消耗相当多?CPU 资源。早期的 Lisp q行环境攉内存垃圾的时间竟占到了系l总运行时间的 40% Q——垃圾收集效率的低下直接造就?Lisp 语言在执行速度斚w的坏名声Q直C天,许多条g反射似地误以为所?Lisp E序都奇慢无比?

W二Q减垃圾收集时的内存占用。这一问题主要出现在复制算法中。尽复制算法在效率上获得了质的H破Q但牺牲一半内存空间的代h仍然是巨大的。在计算机发展的早期Q在内存h?KB 计算的日子里Q浪费客L一半内存空间简直就是在变相敲诈或拦路打劫?

W三Q寻扑֮时的垃圾攉法。无论执行效率如何,三种传统的垃圾收集算法在执行垃圾攉d旉必须打断E序的当前工作。这U因垃圾攉而造成的g时是许多E序Q特别是执行关键d的程序没有办法容忍的。如何对传统法q行改进Q以便实CU在后台悄悄执行Q不影响——或臛_看上M影响——当前进E的实时垃圾攉器,q显然是一件更h战性的工作?

研究者们探寻未知领域的决心和研究工作的进展速度同样令h惊奇Q在 1970 q代?1980 q代的短短十几年中,一大批在实用系l中表现优异的新法和新思\脱颖而出。正是因为有了这些日成熟的垃圾攉法Q今天的我们才能?Java ?.NET 提供的运行环境中随心所Ʋ地分配内存块,而不必担心空间释放时的风险?

 

标记Q整理( Mark-Compact Q算?/font>

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

标记Q整理算法是标记Q清除算法和复制法的有机结合。把标记Q清除算法在内存占用上的优点和复制算法在执行效率上的牚wl合hQ这是所有h都希望看到的l果。不q,两种垃圾攉法的整合ƈ不像 1 ?1 {于 2 那样单,我们必须引入一些全新的思\?1970 q前后, G. L. Steele Q?C. J. Cheney ?D. S. Wise {研I者陆l找C正确的方向,标记Q整理算法的轮廓也逐渐清晰了v来:

在我们熟悉的厅里,q一ơ,垃圾攉机器Z再把厅分成两个南北区域了。需要执行垃圾收集Q务时Q机器h先执行标讎ͼ清除法的第一个步骤,为所有用中的餐巄d标记Q然后,机器人命令所有就者带上有标记的餐巄向餐厅的南面集中Q同时把没有标记的废旧餐巄扔向厅北面。这样一来,机器人只消站在餐厅北面,怀抱垃圄Q迎接扑面而来的废旧餐巄p了?

实验表明Q标讎ͼ整理法的M执行效率高于标记Q清除算法,又不像复制算法那样需要牺牲一半的存储I间Q这昄是一U非常理想的l果。在许多C的垃圾收集器中,Z都用了标记Q整理算法或其改q版本?

 

增量攉Q?Incremental Collecting Q算?/font>

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

对实时垃圾收集算法的研究直接D了增量收集算法的诞生?

最初,Z关于实时垃圾攉的想法是q样的:Zq行实时的垃圾收集,可以设计一个多q程的运行环境,比如用一个进E执行垃圾收集工作,另一个进E执行程序代码。这样一来,垃圾攉工作看上d仿佛是在后台悄悄完成的,不会打断E序代码的运行?

在收集餐巄的例子中Q这一思\可以被理解ؓQ垃圾收集机器h在h们用的同时L废弃的餐巄q将它们扔到垃圾里。这个看似简单的思\会在设计和实现时Cq程间冲H的N。比如说Q如果垃圾收集进E包括标记和清除两个工作阶段Q那么,垃圾攉器在W一阶段中辛辛苦苦标记出的结果很可能被另一个进E中的内存操作代码修改得面目全非Q以至于W二阶段的工作没有办法开展?

M. L. Minsky ?D. E. Knuth 对实时垃圾收集过E中的技术难点进行了早期的研IӞ G. L. Steele ?1975 q发表了题ؓ“多进E整理的垃圾攉Q?Multiprocessing compactifying garbage collection Q?#8221;的论文,描述了一U被后hUCؓ“ Minsky-Knuth-Steele 法”的实时垃圾收集算法?E. W. Dijkstra Q?L. Lamport Q?R. R. Fenichel ?J. C. Yochelson {h也相l在此领域做Z各自的A献?1978 q_ H. G. Baker 发表?#8220;串行计算Z的实时表处理技术( List Processing in Real Time on a Serial Computer Q?#8221;一文,pȝ阐述了多q程环境下用于垃圾收集的增量攉法?

增量攉法的基仍是传统的标讎ͼ清除和复制算法。增量收集算法通过对进E间冲突的妥善处理,允许垃圾攉q程以分阶段的方式完成标记、清理或复制工作。详l分析各U增量收集算法的内部机理是一件相当繁琐的事情Q在q里Q读者们需要了解的仅仅是: H. G. Baker {h的努力已l将实时垃圾攉的梦惛_成了现实Q我们再也不用ؓ垃圾攉打断E序的运行而烦g?

 

分代攉Q?Generational Collecting Q算?/font>

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

和大多数软g开发技术一Pl计学原理总能在技术发展的q程中v到强力催化剂的作用?1980 q前后,善于在研I中使用l计分析知识的技术h员发玎ͼ大多数内存块的生存周期都比较短,垃圾攉器应当把更多的精力放在检查和清理新分配的内存块上。这个发现对于垃圾收集技术的价值可以用巾U的例子概括如下Q?

如果垃圾攉机器够聪明,事先摸清了餐厅里每个人在用餐时用餐巄的习惯——比如有些h喜欢在用前后各用掉一张餐巄Q有的h喜欢自始至终攥着一张餐巄不放Q有的h则每打一个喷嚏就用去一张餐巄——机器h可以制定出更完善的巾U回收计划,qL在h们刚扔掉巾U没多久把垃圾捡走。这U基于统计学原理的做法当然可以让厅的整z度成倍提高?

D. E. Knuth Q?T. Knight Q?G. Sussman ?R. Stallman {h对内存垃圄分类处理做了最早的研究?1983 q_ H. Lieberman ?C. Hewitt 发表了题?#8220;Z对象寿命的一U实时垃圾收集器Q?A real-time garbage collector based on the lifetimes of objects Q?#8221;的论文。这著名的论文标志着分代攉法的正式诞生。此后,?H. G. Baker Q?R. L. Hudson Q?J. E. B. Moss {h的共同努力下Q分代收集算法逐渐成ؓ了垃圾收集领域里的主技术?

分代攉法通常堆中的内存块按寿命分ؓ两类Q年老的和年ȝ。垃圾收集器使用不同的收集算法或攉{略Q分别处理这两类内存块,q特别地把主要工作时间花在处理年ȝ内存块上。分代收集算法垃圾攉器在有限的资源条件下Q可以更为有效地工作——这U效率上的提高在今天?Java 虚拟Z得到了最好的证明?

 

应用潮

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

Lisp 是垃圾收集技术的W一个受益者,但显然不是最后一个。在 Lisp 语言之后Q许许多多传l的、现代的、后C的语a已经把垃圾收集技术拉入了自己的怀抱。随便D几个例子吧:诞生?1964 q的 Simula 语言Q?1969 q的 Smalltalk 语言Q?1970 q的 Prolog 语言Q?1973 q的 ML 语言Q?1975 q的 Scheme 语言Q?1983 q的 Modula-3 语言Q?1986 q的 Eiffel 语言Q?1987 q的 Haskell 语言……它们都先后用了自动垃圾攉技术。当Ӟ每一U语a使用的垃圾收集算法可能不相同,大多数语a和运行环境甚臛_时用了多种垃圾攉法。但无论怎样Q这些实例都说明Q垃圾收集技术从诞生的那一天v׃是一U曲高和寡的“学院z?#8221;技术?

对于我们熟悉?C ?C++ 语言Q垃圾收集技术一样可以发挥巨大的功效。正如我们在学校中就已经知道的那P C ?C++ 语言本nq没有提供垃圾收集机Ӟ但这q不妨碍我们在程序中使用h垃圾攉功能的函数库或类库。例如,早在 1988 q_ H. J. Boehm ?A. J. Demers 成功地实现了一U用保守垃圾收集算法( Conservative GC Algorithmic Q的函数库(参见 http://www.hpl.hp.com/personal/Hans_Boehm/gc Q。我们可以在 C 语言?C++ 语言中用该函数库完成自动垃圾收集功能,必要Ӟ甚至q可以让传统?C/C++ 代码与用自动垃圾收集功能的 C/C++ 代码在一个程序里协同工作?

1995 q诞生的 Java 语言在一夜之间将垃圾攉技术变成了软g开发领域里最为流行的技术之一。从某种角度_我们很难分清I竟?Java 从垃圾收集中受益Q还是垃圾收集技术本w?Java 的普及而扬名。值得注意的是Q不同版本的 Java 虚拟Z用的垃圾攉机制q不完全相同Q?Java 虚拟机其实也l过了一个从单到复杂的发展过E。在 Java 虚拟机的 1.4.1 版中Qh们可以体验到的垃圾收集算法就包括分代攉、复制收集、增量收集、标讎ͼ整理、ƈ行复Ӟ Parallel Copying Q、ƈ行清除( Parallel Scavenging Q、ƈ发( Concurrent Q收集等许多U, Java E序q行速度的不断提升在很大E度上应该归功于垃圾攉技术的发展与完善?

管历史上已l有许多包含垃圾攉技术的应用q_和操作系l出玎ͼ?Microsoft .NET 却是W一U真正实用化的、包含了垃圾攉机制的通用语言q行环境。事实上Q?.NET q_上的所有语aQ包?C# ?Visual Basic .NET ?Visual C++ .NET ?J# {等Q都可以通过几乎完全相同的方式?.NET q_提供的垃圾收集机制。我们似乎可以断aQ?.NET 是垃圾收集技术在应用领域里的一ơ重大变革,它垃圾攉技术从一U单U的技术变成了应用环境乃至操作pȝ中的一U内在文化。这U变革对未来软g开发技术的影响力也许要q远过 .NET q_本n的商业h倹{?

 

大势所?/font>

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

今天Q致力于垃圾攉技术研I的Z仍在不懈努力Q他们的研究方向包括分布式系l的垃圾攉、复杂事务环境下的垃圾收集、数据库{特定系l的垃圾攉{等?

但在E序员中_仍有不少人对垃圾攉技术不屑一,他们宁愿怿自己逐行~写?free ?delete 命oQ也不愿把垃圾收集的重Q交给那些在他们看来既蠢又W的垃圾攉器?

我个为,垃圾攉技术的普及是大势所,q就像生zM来好一h庸置疑。今天的E序员也怼因ؓ垃圾攉器要占用一定的 CPU 资源而对其望而却步,但二十多q前的程序员q曾因ؓ高语言速度太慢而坚持用机器语言写程序呢Q在g速度日新月异的今天,我们是要吝惜那一点儿旉损耗而踟w不前,q是该坚定不Ud站在代码和运行环境的净化剂——垃圾收集的一边呢Q?



]]>
2006-10-28 技术网?/title><link>http://www.shnenglu.com/majianan/archive/2006/10/28/14303.html</link><dc:creator>马嘉?/dc:creator><author>马嘉?/author><pubDate>Sat, 28 Oct 2006 01:59:00 GMT</pubDate><guid>http://www.shnenglu.com/majianan/archive/2006/10/28/14303.html</guid><wfw:comment>http://www.shnenglu.com/majianan/comments/14303.html</wfw:comment><comments>http://www.shnenglu.com/majianan/archive/2006/10/28/14303.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/majianan/comments/commentRss/14303.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/majianan/services/trackbacks/14303.html</trackback:ping><description><![CDATA[ <br /> <font face="Verdana" color="#0000ff"> <font color="#000080"> <strong>1.</strong> </font>   </font> <a class="" title="" target=""> <font face="Verdana" color="#0000ff">解析C++/CLI之头文g、内联函C数组</font> </a> <br /> <br /> <font face="Verdana" color="#0000ff"> <font color="#000080"> <strong>2.</strong> </font>  </font> <a class="" title="" target=""> <font face="Verdana" color="#0000ff"> 解析C++/CLI之头文g、内联函C数组(2)</font> </a> <br /> <br /> <font face="Verdana" color="#0000ff"> <font color="#000080"> <strong>3.</strong> </font>  </font> <a class="" title="" target=""> <font face="Verdana" color="#0000ff"> 解析C++/CLI之头文g、内联函C数组(3)</font> </a> <br /> <br /> <font face="Verdana" color="#000080"> <strong>4.</strong>    <a class="" title="" target="">保卫C++Q安全STL~程中的受检q代?/a><br /><br /><strong>5.</strong>   </font> <img src ="http://www.shnenglu.com/majianan/aggbug/14303.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/majianan/" target="_blank">马嘉?/a> 2006-10-28 09:59 <a href="http://www.shnenglu.com/majianan/archive/2006/10/28/14303.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>人生价值的计算 http://www.shnenglu.com/majianan/archive/2006/10/20/13893.html马嘉?/dc:creator>马嘉?/author>Fri, 20 Oct 2006 03:46:00 GMThttp://www.shnenglu.com/majianan/archive/2006/10/20/13893.htmlhttp://www.shnenglu.com/majianan/comments/13893.htmlhttp://www.shnenglu.com/majianan/archive/2006/10/20/13893.html#Feedback0http://www.shnenglu.com/majianan/comments/commentRss/13893.htmlhttp://www.shnenglu.com/majianan/services/trackbacks/13893.html

本文内容来自|络Q但不知道原创和出处

如果?/span> A ?/span> B ?/span> C ?/span> D……X ?/span> Y ?/span> Z q?/span> 26 个英文字母,分别{于癑ֈ?/span> 1 ?/span> 2 ?/span> 3 ?/span> 4…?4 ?/span> 25 ?/span> 26 q?/span> 26 个数|那么我们p得出如下有趣的结论:

 

努力工作Q?/span> H+A+R+D+W+O+R+K=8+1+18+4+23+15+18+11=98%

知识Q?/span> K+N+O+W+L+E+D+G+E=11+14+15+23+12+5+4+7+5=96%

爱情Q?/span> L+O+V+E=12+5+22+5=54%

好运Q?/span> L+U+C+K=12+21+3+11=47%

 

q些我们通常非常看重的东襉K不是最完满的,虽然它们非常重要。那么,I竟什么能使得生活变得圆满Q?/span>

是金钱吗Q?/span> M+O+N+E+Y=13+15+14+5+25=72%

是领导力吗? L+E+A+D+E+R+S+H+I+P=12+5+1+4+5+18+19+9+16=89%

是性吗Q?/span> S+E+X=19+24+5=48%

 

那么Q什么能使生zd?/span> 100% 得圆满呢Q?/span>

 

心态! A+T+T+I+T+U+D+E=1+20+20+9+20+21+4+5=100%

正是我们对待工作、生zd态度能够使我们的生活辑ֈ 100% 的圆满!



]]>
用指针调用函数的不同形式http://www.shnenglu.com/majianan/archive/2006/09/14/12436.html马嘉?/dc:creator>马嘉?/author>Thu, 14 Sep 2006 02:08:00 GMThttp://www.shnenglu.com/majianan/archive/2006/09/14/12436.htmlhttp://www.shnenglu.com/majianan/comments/12436.htmlhttp://www.shnenglu.com/majianan/archive/2006/09/14/12436.html#Feedback0http://www.shnenglu.com/majianan/comments/commentRss/12436.htmlhttp://www.shnenglu.com/majianan/services/trackbacks/12436.html

用指针调用函数的不同形式
 
Ma Jia nan
2006-1-16
 
    最初一个函数指针必ȝ*操作W(和一ҎP“{换ؓ”一个“真正的”函数才能调用,如下所C:
 
    int r, func(), (*pf)() = func; //函数指针的初始化
    r = (*pf)();  //函数的指针调用Ş?Q等价于 r = func();
 
    函数L通过指针q行调用的,所有“真正的”函数名L隐式的退化ؓ指向该函数的指针Q?正如在对函数指针pf初始化做的那P
 
    int func();
    int (*pf)() = func;
 
    q有点类似数l名的行为(不带下标操作W的数组名会被解释成指向数组首元素的指针Q?

    以上l论表明Q下面的语句也是正确的?
 
    r = pf();     //函数的指针调用Ş?
 
    ANSI C 标准实际上接受Ş?Q这意味着不再需?操作W,但Ş?依然允许。两UŞ式生相同的l果Q但是Ş?让读者更清楚该调用是通过函数指针执行的?
 
 


]]>
序容器操作http://www.shnenglu.com/majianan/archive/2006/09/14/12435.html马嘉?/dc:creator>马嘉?/author>Thu, 14 Sep 2006 02:07:00 GMThttp://www.shnenglu.com/majianan/archive/2006/09/14/12435.htmlhttp://www.shnenglu.com/majianan/comments/12435.htmlhttp://www.shnenglu.com/majianan/archive/2006/09/14/12435.html#Feedback0http://www.shnenglu.com/majianan/comments/commentRss/12435.htmlhttp://www.shnenglu.com/majianan/services/trackbacks/12435.html

    C++ Primer 学习札记  

Ma Jia nan


一 序容器操作之插入(insertQ?/strong>
 
向容器中插入元素有以下几UŞ式:
 
1Q?最一般的形式Q?

   vector<string> svec;
   list<string> slist;

   string s( "MaJianan" );
   slist.insert( slist.begin(), s );
   svec.insert( svec.begin(), s );

insert()第二个参数Q要被插入的|插入到第一个参敎ͼ指向容器中某个位|的iteratorQ指向的位置的前面?

更ؓ随机的插入操作可以如下实玎ͼ

   string s1( "yuanlaishini" );
   list<string>::iterator iter;

   iter = find( slist.begin(), slist.end(), s1 );
   slist.insert( iter, s1 );

find()q回被查扑օ素在容器中的位置Q如果查扑֤败,q回end()iterator.
   
//slist.push_back( value ){h于  ?
slist.insert( slist.end(), value );

 

2Q?在某个位|插入指定数量的元素.
   例如Q在vector的开始处插入10个MaJiananQ?

   vector<string> svec;
   string mjn( "MaJianan" );

   svec.insert( svec.begin(), 10, mjn );

 

3Q向容器插入一D范围内的元素:

 string sa[3] = { "MaJianan", "yuanlaishini", "blog.sina.com.cn"};

   //插入数组中的全部元素
   svec.insert( svec.begin(), sa, sa+3 );

   //插入数组中的部分元素
   svec.insert( svec.begin() + svec.size()/2, sa+1, sa+3 );  

 

4Q通过一对iterator来标记带插入值的范围Q可以是另一个vector

例一Q?br />   //插入svec中含有的元素Q从svec2中间开?br />   svec2.insert( svec2.begin() + svec2.size()/2, svec.begin(), svec.end() );

   例二Q?br />   //把sevc中的元素插入到slist中sValue的前?br />   list<string> slist;
   list<string>::iterator iter = find( slist.begin(), slist.end(), sValue );
   slist.insert( iter, svec.begin(), svec.end() );


?序容器操作之删除(eraseQ?/strong>

1Q?删除单个元素

list<string> slist;
... ...
sting sValue( "yuanlaishini" );
list<string>::iterator iter=find( slist.begin(), slist.end(), sValue );
if( iter!=slist.end() )
       slist.erase( iter );

 

2Q?删除有一对iterator标记的一D范围内的元?

//删除所有元?br />slist.erase( slist.begin(), slist.end() );

//删除部分元素
例一Q?br />slist.erase( slist.begin()+slist.size()/2, slist.end() );

例二Q?br />list<string>::iterator first, last;
first=find( slist.begin(), slist.end(). value1);
last=find( slist.begin(), slist.end(). value2);
//验first和last的有效?br />slist.erase( first, last );


3Q?与push_back()相对应,pop_back()删除容器的末օ素?


?序容器操作之赋?=)和对?swap)

//slist1含有8个元?br />//slist2含有16个元?br />1)如果 slist1 = slist2;
 
  slist1拥有与被拯容器相同的元素数?--16.slist2?6个元素,没有变化?br />  slist1中原来的8个元素被删除(调用string的析构函?

2)如果 slist1.swap( slist2 );
 
  slist1现在?6个元素,而slist2函数slist1中原有的8个元素的拯
  如果两个容器长度不同Q则重置容器的长度?


 

 



]]>
定基类有虚析购函数http://www.shnenglu.com/majianan/archive/2006/09/14/12434.html马嘉?/dc:creator>马嘉?/author>Thu, 14 Sep 2006 02:05:00 GMThttp://www.shnenglu.com/majianan/archive/2006/09/14/12434.htmlhttp://www.shnenglu.com/majianan/comments/12434.htmlhttp://www.shnenglu.com/majianan/archive/2006/09/14/12434.html#Feedback0http://www.shnenglu.com/majianan/comments/commentRss/12434.htmlhttp://www.shnenglu.com/majianan/services/trackbacks/12434.html 当通过基类的指针去删除zcȝ对象Q而基cL没有虚析购函数的时候,l果是不可定的。(实际q行时常发生的情冉|Q派生类的析购函数永q不会被调用Q?
 
虚函数的目的是让zcd制定自己的行为,所以几乎所有的基类都有虚函数?
 
如果某个cM包含虚函敎ͼ那一般是表示他将不作为基cL使用Q当一个类不准备做基类使用的时候,使析购函Cؓ虚一般是个错误的选择?


]]>
极限~程――理解和实践Q{载)http://www.shnenglu.com/majianan/archive/2006/08/26/11728.html马嘉?/dc:creator>马嘉?/author>Sat, 26 Aug 2006 02:15:00 GMThttp://www.shnenglu.com/majianan/archive/2006/08/26/11728.htmlhttp://www.shnenglu.com/majianan/comments/11728.htmlhttp://www.shnenglu.com/majianan/archive/2006/08/26/11728.html#Feedback0http://www.shnenglu.com/majianan/comments/commentRss/11728.htmlhttp://www.shnenglu.com/majianan/services/trackbacks/11728.html作ؓ敏捷软g开发领域主的开发方法,极限~程与其说是一U系l的Ҏ学,倒更像是一pd最佛_늚有机l合。在q些最佛_践中Q有些是已经qؓZ所接受的(如编码标准)Q而更多的则极具颠覆性,初看之下让hg难以接受?/font>

本文中,我将针对q些看似怪异的最佛_践阐q我的观点,q简q我对实施这些最佛_늚一些思考?/font>

一、计划游?/font>

能够把计划叫?#8220;游戏”是需要一定勇气的。在传统的Y件开发方法学中,计划是D重的一环,在制订计划前需要仔l的估算Q在计划实施的过E中Q还要不停的跟踪、修正,直至整个目完成?/font>

而在XP中,计划g要轻松许多。这q不是因划本w变得草率和无关痛痒Q而是得益于XP的小版本发布思维。Y件的一个版本是如此短小单,以至于对它进行完整的评估、预、跟t和修正要容易许多。事实上QXP中采用的计划方式Q业务h员和开发h员共同参与,各司其职Q在大多数现代Y件企业中早已采用Q但是由于项目过于庞大,很难在开始阶D制订出完善的计划。而在XP中,Z只需要针对一个一两个月的项目进行跟t和理Q无形中降低了计划的风险?/font>

二、隐?/font>

    在XP中,Zl常会用隐L代替传统开发过E中的体pȝ构设计。从指导开发的角度来说Q隐M乎不够精,Ҏ让h误解。但是,对于hcM背景的同一个项目组中的开发h员来_隐喻则更便于理解和交。很难想象两个程序员面对着一张庞大的体系l构图时能够真正有效的沟通,而隐d好的解决了这个问题?/font>

三、简单设?/font>

不知道从什么时候开始,开发h员习惯了为明天而设计。一个开发h员设计了一个复杂的cȝ承结构,只是Z提高E序的所谓灵zL。没人知道这样g|q不是Y件的每一个部分都需要扩展。但是,对于传统的Y件开发h员来_q么做又是迫不得巌Ӏ如果没有预先做好准备,在变化来临时׃措手不及Q付出沉重的代h?/font>

但是在XP中,版本发行的Ҏ使得变化q不那么可怕,而重构的q泛采用Q得代码L可以在需要时变得更加灉|。此外,׃你的代码L会被别h审查Q代码集体所有权和结对编E)Q因此也可以避免q于q求单而忽视了重要的细节?/font>

四、测试优?/font>

没有代码要测试程序有什么用Q这是测试优先最Ҏ让h误解的地斏V测试优先能够让开发h员更清楚的认识到Q程序将会如何被使用。通过对不同的试用例的思考,开发h员也能够更清晰的认识到程序的功能外g。而更多的其他的开发h员,则通过试用例可以获得一份精的使用手册Q在q䆾使用手册中,描述了作者考虑到的所有输入和输出l果Q这样不仅便于h们了解程序,更增加了发现E序错误的机会(~失的测试用例往往体现Z者忽视的某些使用情况Q?/font>

五、结对编E?/font>

两个E序员坐在一P能够提高开发效率吗Q程序员N不是一高傲的猫,习惯于离烦居,把头抬得高高吗?

事实q如此。在一个正的、合理的、能够实现的大目标下Q程序员们不仅能够和q_处,更可以相互合作,创造出优秀的、高质量的程序。沟通一直是软g目理中的一个重要议题,而结对编E提供了一个十分有效的沟通渠道。此外,l对~程也更Ҏ让新入团体。在几个高E序员的指引下,他会更容易找出程序的脉络Q把握程序的思想。较之正规的培训Q这U方式更L也更有效。对于团队中的所有程序员来说Q结对编E都是一个了解其他h设计思想的机会,通过l对~程Q能够更好的实现代码集体所有权Q也能够降低因ؓ人员动造成的风险?/font>

l对~程最大的好处在于Q能够极大的减少E序中潜在变化的可能性。两个h通过交流互相交换自己对程序的不同理解Q更Ҏ扑ևE序中可能出现的变化或错误,从而ɽE序更加可靠和健壮?/font>

六、持l集?/font>

集成一直是最费力的工作之一Q本来工作的好好的代码,攑֜一起就不能q{Q更p糕的是成百上千条不知所云的错误码,没有人知道这些错误码来自何处。这是每个项目几乎都会遇到的最困难的阶D,E序员们必须集合在一P阅数量巨大的接口定义文Ӟ反复查看代码Q同时还要不断的做出承诺?/font>

持箋集成正是解决上述问题的方法。通过多次、小增量的集成,我们L能够以最快的速度定位错误出现的位|(因ؓ增加的代码很)Q结合大量测试用例,我们也可以确保每一个集成版本都可能的可靠?/font>

此外Q持l集成几乎可以在M旉向我们提供一个可以工作的版本Q我们可以将q个版本用于内部讨论和测试、客户展C、客h试、小版本发布{等Q这使得我们不需要花费太多的旉对现有的E序修修补补Q以生成一个demo?/font>

上文单叙qCXP中常会引起争议的六个最佛_늚优点。下面本文将l合实际谈谈实施XP中需要注意的一些问题?/font>

一、适用性问?/font>

XP理论在提出时Q明的说明QXP是适用于中型团队在需求不明确或者迅速变化的情况下进行Y件开发的轻量U方法。这意味着QXPq不适用于所有情c在准备实施XP前,你也讔R要仔l评估项目的具体情况Q以军_是否真的需要采用XP?/font>

二、最佛_践间的关?/font>

XP的一个特ҎQ它所推崇的最佛_践几乎L和其它实践关联紧密,在实施一Ҏ佛_跉|Q如果不同时实施其它实践Q往往难以辑ֈ最初的目的。因此,在实施XPӞ需要仔l研I各实践间的关联,以确定最佳的实施Ҏ?/font>

三、宽杄环境

XP是一U追求自然的工作Ҏ。它所倡导的是Q程序员们以最自然开发的方式完成他们的工作。对于习惯了传统开发方法严格管理制度的理人员来说Q这往往是很难接受的。于是就出现了,虽然最高决{h军_实施XPQ但理层却无法Q或不愿Q给开发h员提供宽杄环境。在一个古板僵化的Ҏ里,开发h员不会真正的回复自然Q他们会装作正在实践XPQ但事实上,他们依然在老\上行赎ͼ可以见到很多q样的例子,比如一些虚张声势的试用例{等Q?/font>

四、忍受变?/font>

XP对于传统软g目理思想的冲击,可能会很多理人员感到不舒服。也许XP一l实施,׃l项目组带来d覆地的变化。如果这L变化让你感到恐惧Q那么请暂时忍耐,你不能肯定这U变化不好,除非你亲眼看到。到那时再决定也不迟?/font>

五、慢慢来

实施XP的过E不能操之过急。最好的Ҏ是,在部分项目组中先行实施,实施时也不需要同时实施所有实践(但要注意各个实践间的兌问题Q。有的时候你会发玎ͼ在实施了部分实践后,其它的实践也成ؓ水到渠成的事情。当l过仔细评估Q确信XP在项目组中确实有效后Q再逐步在企业范围内推广Q必要的时候,需要采取自愿的原则Q由目l的成员军_是否需要实施XP?/font>

以上x我在软g工程q程评中以及^时工作、学习中对XP的一些认识?/font>


来源Q?/font> http://blog.csdn.net/leasun/archive/2006/08/15/1067508.aspx



]]>
iostream ?iostream.h 的区?http://www.shnenglu.com/majianan/archive/2006/08/26/11727.html马嘉?/dc:creator>马嘉?/author>Sat, 26 Aug 2006 01:49:00 GMThttp://www.shnenglu.com/majianan/archive/2006/08/26/11727.htmlhttp://www.shnenglu.com/majianan/comments/11727.htmlhttp://www.shnenglu.com/majianan/archive/2006/08/26/11727.html#Feedback5http://www.shnenglu.com/majianan/comments/commentRss/11727.htmlhttp://www.shnenglu.com/majianan/services/trackbacks/11727.html                                          < iostream > ?< iostream.h > 的区?/font>

关键词:< iostream > ?< iostream.h >
 
你写E序的时候,?lt; iostream >q是< iostream.h >Q?
你知道它们有什么区别么Q还是认Z们根本就是一LQ?
下面听我l你吹(文中U属个ha论,不涉及国家机密,h心阅读,若{载请注明出处作者^-^Q?
                              ---majianan
 
 
其实没有< iostream.h >q样的东?--- 标准化委员会在简化非C标准头文件时?lt; iostream > 取代了它。但又没有完全取?lt; iostream.h >的用,q且很多~译器都同时支持< iostream >?lt; iostream.h >Q造成现在的局面,老大Q标准化委员会)实有不得已的苦街?
 
话说当年Q在标准化委员会动手重徏新的标准库的时候,遇到了问题。ؓ了避免类名函数名的冲H问题,引入了名字空间stdQ但无数现有的C++代码都依赖于使用了多q的伪标准库中的功能Q例如,声明?lt; iostream.h >?lt; complex.h >{头文g中的功能。现有Y件没有针对用名字空间而进行相应的设计或者升U,如果用std来包装标准库D现有代码不能使用Q那手底下的弟Q程序员Q是不会同意的?
 
标准化委员会Z拉拢人心Q吸引更多的人入会,军_为包装了std的那部分标准库构建新的头文g名。将现有C++头文件名中的.hLQ所以就出现?lt; iostream.h>?lt; iostream >{很多双胞胎。对于C头文Ӟ采用同样Ҏ但在每个名字前还要添加一个CQ所以C?lt;string.h>变成?lt;cstring>?
 
旧的C++头文件是官方明确反对使用的,但旧的C头文件则没有Q以保持对C的兼Ҏ)。其实编译器刉商不会停止对客L有Y件提供支持,所以在可以预计的将来,旧的C++头文件还会嚣张一D|间?
 
如果能明白字W串头文件的使用QD一反三Q其他的也差不多会用了?
 
<string.h>是旧的C头文Ӟ对应的是Zchar*的字W串处理函数Q?
<string>是包装了std的C++头文Ӟ对应的是新的strngc;
<cstring>是对应旧的C头文件的std版本?
 
好像跑远了,a归正传。如果你的编译器都同时支?lt; iostream >?lt; iostream.h >Q那使用#include < iostream >Q得到的是置于名字空间std下的iostream库的元素Q如果?include < iostream.h >Q得到的是置于全局I间的同L元素。在全局I间获取元素会导致名字冲H,而设计名字空间的初衷正是用来避免q种名字冲突的发生。还有,打字?lt; iostream >?lt; iostream.h >两个字Q所以我会?lt; iostream > ^-^
 
CQ睡了?
 
 
                                      马嘉?
                                  2005-12-26 午夜


]]>
关于 sizeof() 的一些思?http://www.shnenglu.com/majianan/archive/2006/08/25/11682.html马嘉?/dc:creator>马嘉?/author>Fri, 25 Aug 2006 01:25:00 GMThttp://www.shnenglu.com/majianan/archive/2006/08/25/11682.htmlhttp://www.shnenglu.com/majianan/comments/11682.htmlhttp://www.shnenglu.com/majianan/archive/2006/08/25/11682.html#Feedback1http://www.shnenglu.com/majianan/comments/commentRss/11682.htmlhttp://www.shnenglu.com/majianan/services/trackbacks/11682.html

                                       关于 sizeof() 的一些思?/font> 
                                                         马嘉?br />
关键词: sizeof

q是|上的一个帖子,最初来自那里已l记不得了,不过我觉得很不错?/font>

我对原文做了一些修改,q添加了一些内宏V如果有什么错误的地方Q请大家指正Q谢谢~~

                       --- majianan 2005-12-19

 

0.关键?/font> QsizeofQ字节对齐,cd大小

前向声明Q?/font>
    sizeofQ一个其貌不扬的家伙Q引无数菜鸟竟折?

    虾我当初也没少犯迷p,U着“辛苦我一个,q福千万人”的伟大思想,我决定将其尽可能详细的ȝ一下?


    但当我ȝ的时候才发现Q这个问题既可以单,又可以复杂。所以本文有的地方ƈ不适合初学者,甚至都没有必要大作文章。但如果你想“知其然Q更知其所以然”的话,那么q篇文章对你或许有所帮助?br />   

    菜鸟我对C++的掌握尚未深入,其中不乏错误Q欢q各位指正啊

1. 定义Q?br />     sizeof是何方神圣?

    sizeof ?C/C++ 中的一个操作符QoperatorQ是也。简单说其作用就是返回一个对象或者类型所占的内存字节数?br />
MSDN上的解释为:

The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types).This keyword returns a value of type size_t.

    其返回值类型ؓsize_tQ在头文件stddef.h中定义。这是一个依赖于~译pȝ的|一般定义ؓ

typedef unsigned int size_t;

    世上~译器林林L,但作Z个规范,它们都会保证char、signed char和unsigned char的sizeofgؓ1Q毕竟char是我们编E能用的最数据类型?br />
2. 语法Q?/font>
    sizeof有三U语法Ş式,如下Q?br />    1) sizeof( object );    // sizeof( 对象 );
    2) sizeof( type_name ); // sizeof( cd );
    3) sizeof object;       // sizeof 对象;

所以,
int i;
sizeof( i );     // ok
sizeof i;        // ok
sizeof( int );   // ok
sizeof int;      // error

既然写法2可以用写?代替Qؓ求Ş式统一以及减少我们大脑的负担,W?U写法,忘掉它吧Q?

实际上,sizeof计算对象的大也是{换成对对象类型的计算。也是_同种cd的不同对象其sizeof值都是一致的?

q里Q对象可以进一步g伸至表达式,即sizeof可以对一个表辑ּ求倹{编译器Ҏ表达式的最l结果类型来定大小Q一般不会对表达式进行计?

例如Q?

sizeof( 2 );        // 2的类型ؓintQ所以等价于 sizeof( int );
sizeof( 2 + 3.14 ); // 3.14的类型ؓdoubleQ?也会被提升成doublecdQ所以等价于 sizeof( double );

    sizeof也可以对一个函数调用求|?font color="#0000ff">l果是函数返回类型的大小Q函数ƈ不会被调用?/font>我们来看一个完整的例子Q?

*********************************************************

char foo()
{
    printf("foo() has been called.\n");
    return 'a';
}
int main()
{
    size_t sz = sizeof( foo() );   // foo() 的返回值类型ؓcharQ所以sz = sizeof(char)Q但函数foo()q不会被调用
    printf("sizeof( foo() ) = %d\n", sz);
}

*********************************************************

C99标准规定Q函数、不能确定类型的表达式以及位域(bit-fieldQ成员不能被计算sizeof|即下面这些写法都是错误的Q?

    sizeof( foo );     // error
    void foo2() { }
    sizeof( foo2() );  // error
    struct S
    {
        unsigned int f1 : 1;
        unsigned int f2 : 5;
        unsigned int f3 : 12;
    };
    sizeof( S.f1 );   // error


3. sizeof的常量?/font>


    sizeof的计发生在~译时刻Q所以它可以被当作常量表辑ּ使用。如Q?

char ary[ sizeof( int ) * 10 ];   // ok

最新的C99标准规定sizeof也可以在q行时刻q行计算。如下面的程序在Dev-C++中可以正执行:

int n;
n = 10;        // n动态赋?br />char ary[n];   // C99也支持数l的动态定?br />printf("%d\n", sizeof(ary)); // ok. 输出10

但在没有完全实现C99标准的编译器中就行不通了Q上面的代码在VC6中就通不q编译。所以我?font color="#0000ff">最好还是认为sizeof是在~译期执行的Q这样不会带来错误,让程序的可移植性强些?


4. 基本数据cd的sizeof

q里的基本数据类型指short、int、long、float、doubleq样的简单内|数据类型。由于它们都是和pȝ相关的,所以在不同的系l下取值可能不同。这务必引v我们的注意,量不要在这斚wl自q序的UL造成ȝ?

一般的Q在32位编译环境中Qsizeof(int)的取gؓ4?


5. 指针变量的sizeof

学过数据l构的你应该知道指针是一个很重要的概念,它记录了另一个对象的地址?font color="#0000ff">既然是来存放地址的,那么它当然等于计机内部地址ȝ的宽度?/font>所以在32位计机中,一个指针变量的q回值必定是4Q注意结果是以字节ؓ单位Q。可以预计,在将来的64位系l中指针变量的sizeofl果??

*********************************************************

char* pc = "abc";
int* pi;
string* ps;
char** ppc = &pc;
void (*pf)(); // 函数指针
sizeof( pc ); // l果?
sizeof( pi ); // l果?
sizeof( ps ); // l果?
sizeof( ppc );// l果?
sizeof( pf ); // l果?

*********************************************************

指针变量的sizeofg指针所指的对象没有M关系Q正是由于所有的指针变量所占内存大相{,所以MFC消息处理函数使用两个参数WPARAM、LPARAMp传递各U复杂的消息l构Q用指向结构体的指针)?


6. 数组的sizeof

数组的sizeof值等于数l所占用的内存字节数Q如Q?

char a1[] = "abc";
int a2[3];
sizeof( a1 ); // l果?Q字W?末尾q存在一个NULLl止W?br />sizeof( a2 ); // l果?*4=12Q依赖于intQ?

一些朋友刚开始时把sizeof当作了求数组元素的个敎ͼ现在Q你应该知道q是不对的。那么应该怎么求数l元素的个数呢?

EasyQ通常有下面两U写法:

int c1 = sizeof( a1 ) / sizeof( char );    // 总长?单个元素的长?br />int c2 = sizeof( a1 ) / sizeof( a1[0]);    // 总长?W一个元素的长度


写到q里Q提一问,下面的c3Qc4值应该是多少呢?

*********************************************************

void foo3(char a3[3])
{
    int c3 = sizeof( a3 ); // c3 ==
}
void foo4(char a4[])
{
    int c4 = sizeof( a4 ); // c4 ==
}

*********************************************************

也许当你试图回答c4的值时已经意识到c3{错了,是的Qc3!=3?

q里函数参数a3已不再是数组cdQ而是蜕变成指针?/font>相当于char* a3Qؓ什么仔l想惛_不难明白?

我们调用函数foo1ӞE序会在栈上分配一个大ؓ3的数l吗Q不会!

数组是“传址”的Q调用者只需实参的地址传递过去,所以a3自然为指针类型(char*Q,c3的g׃ؓ4?


7.string的sizeof
一个string的大与它所指向的字W串的长度无?/font>?br />
*********************************************************
string st1("blog.sina.com.cn");
string st2("majianan");
string st3;
string *ps = &st1;
cout << "st1: " << sizeof(st1) << endl;
cout << "st2: " << sizeof(st2) << endl;
cout << "st3: " << sizeof(st3) << endl;
cout << "ps: " << sizeof(ps) << endl;
cout << "*ps: " << sizeof(*ps) << endl;
*********************************************************

输出l果为:
st1Q?28
st2Q?28
st3Q?28
psQ?4
*psQ?28
*********************************************************
对于不同的STLQStringcȝl构定义会有所不同
所以不同的工具Q例如VC++Q和.NETQ结果会有所不同Q?br />在VC++6.0中(我的机器Q结果是16
?NET2003中结果是28
但是对于同一个编译器Q那么它的结果都是一定的


8.引用的sizeof

sizeof操作W应用在引用cd上的时候,q回的是包含被引用对象所需的内存长度(卌引用对象的大)

*********************************************************
cout << "short:\t" << sizeof(short) << endl;
cout << "short*:\t" << sizeof(short*) << endl;
cout << "short&:\t" << sizeof(short&) << endl;
cout << "short[4]:\t" << sizeof(short[4]) << endl;
cout << "int&:\t" << sizeof(int&) << endl;
*********************************************************

输出l果为:
shortQ?2
short*Q?4
short&Q?2
short[4]Q?8
int&Q?4


9. l构体的sizeof

q是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体Q?

struct S1
{
    char c;
    int i;
};

问sizeof(s1){于多少Q?

聪明的你开始思考了Qchar?个字节,int?个字节,那么加v来就应该??

是这样吗Q?

你在你机器上试过了吗Q?

也许你是对的Q但很可能你是错的!

VC6中按默认讄得到的结果ؓ8?br />
    WhyQؓ什么受伤的L我?

请不要沮丧,我们来好好琢一下sizeof的定?—?sizeof的结果等于对象或者类型所占的内存字节数。好吧,那就让我们来看看S1的内存分配情况:

S1 s1 = { 'a', 0xFFFFFFFF };

定义上面的变量后Q加上断点,q行E序Q观察s1所在的内存Q你发现了什么?

以我的VC6.0ZQs1的地址?x0012FF78Q其数据内容如下Q?

0012FF78: 61 CC CC CC FF FF FF FF

发现了什么?怎么中间Ҏ?个字节的CCQ?

看看MSDN上的说明Q?

When applied to a structure type or variable, sizeof returns the actual size, which may include padding bytes inserted for alignment.

原来如此Q这是传说中的字节寚w啊!一个重要的话题出现了?

Z么需要字节对齐?

计算机组成原理教导我们,q样有助于加快计机的取数速度Q否则就得多花指令周期了?

为此Q编译器默认会对l构体进行处理(实际上其它地方的数据变量也是如此Q,让宽度ؓ2的基本数据类型(short{)都位于能?整除的地址上,让宽度ؓ4的基本数据类型(int{)都位于能?整除的地址上?/font>以此cLQ这P两个C间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了?

让我们交换一下S1中char与int的位|:

struct S2
{
    int i;
    char c;
};

看看sizeof(S2)的结果ؓ多少Q怎么q是8?

再看看内存,原来成员c后面仍然?个填充字节?

q又是ؓ什么啊Q别着急,下面ȝ规律?

    字节寚w的细节和~译器实现相养I但一般而言Q满三个准则:
    1) l构体变量的首地址能够被其最宽基本类型成员的大小所整除Q?br />    2) l构体每个成员相对于l构体首地址的偏U量QoffsetQ都是成员大的整数倍,如有需要编译器会在成员之间加上填充字节Qinternal addingQ;
    3) l构体的dؓl构体最宽基本类型成员大的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing paddingQ?br />
    对于上面的准则,有几炚w要说明:
1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏U量了呢Q?

因ؓ有了W?点存在,所以我们就可以只考虑成员的偏U量Q这h考v来简单。想想ؓ什么?

l构体某个成员相对于l构体首地址的偏U量可以通过宏offsetof()来获得,q个宏也在stddef.h中定义,如下Q?

#define offsetof(s,m) (size_t)&(((s *)0)->m)

例如Q想要获得S2中c的偏U量Q方法ؓ

size_t pos = offsetof(S2, c);// pos{于4


2) 基本cd是指前面提到的像char、short、int、float、doubleq样的内|数据类型。这里所说的“数据宽度”就是指其sizeof的大。由于结构体的成员可以是复合cdQ比如另外一个结构体Q所以在L最宽基本类型成员时Q应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合cd作ؓ整体看待?

q里叙述h有点拗口Q思考v来也有点挠头Q还是让我们看看例子吧(具体数g以VC6ZQ以后不再说明)Q?

struct S3
{
    char c1;
    S1 s;
    char c2;
};

S1的最宽简单成员的cd为intQS3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型ؓint。这P通过S3定义的变量,其存储空间首地址需要被4整除Q整个sizeof(S3)的g应该?整除?

c1的偏U量?Qs的偏U量呢?q时s是一个整体,它作为结构体变量也满_面三个准则,所以其大小?Q偏U量?Qc1与s之间侉K?个填充字节,而c2与s之间׃需要了Q所以c2的偏U量?2Q算上c2的大ؓ13Q?3是不能被4整除的,q样末尾q得补上3个填充字节。最后得到sizeof(S3)的gؓ16?


    通过上面的叙qͼ我们可以得到一个公式:
    l构体的大小{于最后一个成员的偏移量加上其大小再加上末填充字节数目Q?/strong>卻I

sizeof( struct ) = offsetof( last item ) + sizeof( last item ) + sizeof( trailing padding )

 

10.cȝsizeof
 
cȝsizeof值等于类中成员变量所占用的内存字节数。如Q?br />
****************************************************************
 
class A
{
 public:
     int b;
     float c;
     char d;
};

int main(void)
{
  A object;
  cout << "sizeof(object) is " << sizeof(object) << endl;
  return 0 ;
}
 
***************************************************************
 
 
输出l果?2Q我的机器上sizeof(float)gؓ4Q字节对其前面已l讲q)?
 
不过需要注意的是,如果cM存在静态成员变量,l果又会是什么样子呢Q?
 
***************************************************************

class A
{
 public:
     static int a;
     int b;
     float c;
     char d;
};

int main()
{
  A object;
  cout << "sizeof(object) is " << sizeof(object) << endl;
  return 0 ;
}
 
**************************************************************
 
 
16Q不寏V结果仍然是12.

因ؓ在程序编译期_已lؓstatic变量在静态存储区域分配了内存I间Qƈ且这块内存在E序的整个运行期间都存在?

而每ơ声明了cA的一个对象的时候,对象在堆上,Ҏ对象的大分配内存?
 
如果cA中包含成员函敎ͼ那么又会是怎样的情况呢Q看下面的例?
 
*************************************************************

class A
{
 public:
     static int a;
     int b;
     float c;
     char d;
     int add(int x,int y)
     {
       return x+y;
     }
};

int main()
{
  A object;
  cout << "sizeof(object) is " << sizeof(object) << endl;
  b = object.add(3,4);
  cout << "sizeof(object) is " << sizeof(object) << endl;
  return 0 ;
}
 
***************************************************************
 
l果仍ؓ12?font color="#0000ff">
因ؓ只有非静态类成员变量在新生成一个object的时候才需要自q副本?
所以每个非静态成员变量在生成新object需要内存,而function是不需要的?
 
 
注:C++中的多态和虚承也是非帔R要的东西Q不q比较复杂,~译器不同,l节也有所不同。(以后慢慢研究Q哈哈)


]]>
生活感悟http://www.shnenglu.com/majianan/archive/2006/07/17/10172.html马嘉?/dc:creator>马嘉?/author>Mon, 17 Jul 2006 14:14:00 GMThttp://www.shnenglu.com/majianan/archive/2006/07/17/10172.htmlhttp://www.shnenglu.com/majianan/comments/10172.htmlhttp://www.shnenglu.com/majianan/archive/2006/07/17/10172.html#Feedback0http://www.shnenglu.com/majianan/comments/commentRss/10172.htmlhttp://www.shnenglu.com/majianan/services/trackbacks/10172.html

辛辛苦苦,q舒服日?
舒舒服服,q辛苦日?



]]>
厚道http://www.shnenglu.com/majianan/archive/2006/07/17/10147.html马嘉?/dc:creator>马嘉?/author>Mon, 17 Jul 2006 01:13:00 GMThttp://www.shnenglu.com/majianan/archive/2006/07/17/10147.htmlhttp://www.shnenglu.com/majianan/comments/10147.htmlhttp://www.shnenglu.com/majianan/archive/2006/07/17/10147.html#Feedback0http://www.shnenglu.com/majianan/comments/commentRss/10147.htmlhttp://www.shnenglu.com/majianan/services/trackbacks/10147.html
  • 锲诃夫说Q有教养不是吃饭不洒汤,是别人洒汤的时候别ȝ他?
  • 有一个相似的国俗语_犯过错不是稀奇的事,E奇的是别人犯错的时候别去讥W他?
  • “别ȝ他”和“别去讥W他”是一U做人风范,在中国叫做“厚道”?
  • 厚道不是ҎQ虽然也可以当方法训l自己。它是h的本性。厚道之于hQ是在什么也没做之中做了很大的事情,锲诃夫称之ؓ“教兠Z?
  • 如果d分ؓ显性与隐性,厚道h隐性特征?
  • 厚道不是愚钝Q很多时候像愚钝。所谓“贵语迟”,q在对一个h一件事的评h着Q君子讷于言。尤其在别h蒙羞之际Q“迟”的评h保全了别人的面子。真正的愚钝是不明曲_而厚道乃是明白而又心存善良Q以宽怀l别Z个补救的Z?
  • 厚道者能沉得住气。厚道不一定得到厚道的回报Q但厚道之ؓ厚道在不图回报Q随他去。急功q利的hq离厚道?
  • 在h际交往上,厚道是基矟뀂它q一时一事的犀利,是别人经q回味的赞赏。处世本无方法,也L一些高明超方法,那就是品根{品格可以发光,Ҏ只是工具。厚道是l得赯验的高品根{?
  • 厚道是冰水深层的劲流Q它有力量,但表面不hL?
  • 厚道的h有主张。和E泥,做好人,是乖巧之表现Q与“厚”无兟뀂无准则Q无界限Q是p涂之表玎ͼ与“道”无兟?/font>
  • 厚道的h也有可能倔强Q也可能不入俗流Q宁可憨Q而不巧?
  • 厚,是长麦子的土壤之厚,墙体挡风之厚。厚德尔后蝲物,做h辑ֈq样的境界,已然得道?


  • ]]>
    þ99ù龫Ʒ66 | ޾ƷҾþþþþ| ޹ƷþþþþԻ| þþþþAŷAV| þþȹ͵ۺ| avttþþƷ| aaþʦ2021Ʒ | þõӰ2021| þۺɫݺ| 91ƷɫۺϾþ| þ޾Ʒϵַ| 91ƷɫۺϾþ| 99þùƷһ | ƷȾþëƬ| vavavaþ| һŷƬþ | 69Ʒþþþվ| þþƷ99þ˿| 2020þþƷ| ձ޷츾þþþþ| þӰӹ| پþþƷþ| 97þۺɫۺɫhd| ҹþþþþþþõӰ| ŷ þ| ŷ˼Ծþ| þþƷŷƬ| ŷƷһþĻ| ۺɫۺϾþۺ| þþþƷ| ƷŮþþAV| þþƷŷ| Ʒþþø| þerƵᆱƷ| ޹˾þۺ3d | 99þùۺϾƷŮͬͼƬ| þþþavӰ| þø߳һëƬ| þþþ޾Ʒһ | Ʒþþþaaaa| þ99޸ۿҳ|