﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-xuht</title><link>http://www.cppblog.com/xuht/</link><description /><language>zh-cn</language><lastBuildDate>Wed, 08 Apr 2026 06:57:06 GMT</lastBuildDate><pubDate>Wed, 08 Apr 2026 06:57:06 GMT</pubDate><ttl>60</ttl><item><title>设计模式在C语言中的应用--读nginx源码（转）</title><link>http://www.cppblog.com/xuht/archive/2012/02/01/164797.html</link><dc:creator>xuht</dc:creator><author>xuht</author><pubDate>Wed, 01 Feb 2012 10:01:00 GMT</pubDate><guid>http://www.cppblog.com/xuht/archive/2012/02/01/164797.html</guid><wfw:comment>http://www.cppblog.com/xuht/comments/164797.html</wfw:comment><comments>http://www.cppblog.com/xuht/archive/2012/02/01/164797.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xuht/comments/commentRss/164797.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xuht/services/trackbacks/164797.html</trackback:ping><description><![CDATA[<p>市面上的&#8220;设计模式&#8220;书籍文章，皆针对Java/C++/C#等面向对象语言，似乎离开了面向对象的种种特性，设计模式就无法实现，没有用武之地了。</p>
<p><br /></p>
<p>是这样吗？设计模式的概念是从建筑领域引入的，本身从没歧视过面向过程编程语言，它只是对一类问题的普遍解决方案而已。面向对象语言因为有类、多态等特点，使得开发者们容易达到：隐藏细节、封装变化，而这与设计模式的目的比较一致，所以大师们爱把设计模式与面向对象语言二位一体的使用。然而，存在即合理，C语言直到今日仍然在大型软件工程中担纲主角，其种种设计方法其实与我们通常见到的设计模式本质是相同的。例如nginx这个纯C语言写就的的高性能WEB服务器，就有许多地方使用到了市面书籍提到的设计模式。下面通过nginx源码来看看C语言是怎么做的。当然，UML图都是我根据代码意图所画，并不准确（C语言真没法画UML），只用于方便理解，呵呵。</p>
<p><br /></p>
<p>strategy模式：</p>
<p>该模式用于客户代码在&#8220;无知&#8221;状态下，可以使用种种不同的实现。下面我们以nginx对网络IO操作的封装部分来看看C语言的实现吧。</p>
<p>设计模式就是通过封装变化来解耦，所以，我们先要找出网络IO操作的变化点来。nginx是跨平台的，它会支持linux、freebsd、solaris等操作系统，而每个操作系统的网络IO操作是不同的，这就是变化点了。<br /></p>
<p>&nbsp;</p>
<p>所以，nginx首先定义了ngx_os_io_t来封装这些变化。</p>
<p>&nbsp;</p>
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools"><strong>[cpp]</strong> <a class="ViewSource" title="view plain" href="http://blog.csdn.net/russell_tao/article/details/7220237#"><u><font color="#800080">view plain</font></u></a><a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/russell_tao/article/details/7220237#"><u><font color="#800080">copy</font></u></a><a class="PrintSource" title="print" href="http://blog.csdn.net/russell_tao/article/details/7220237#"><u><font color="#800080">print</font></u></a><a class="About" title="?" href="http://blog.csdn.net/russell_tao/article/details/7220237#"><u><font color="#800080">?</font></u></a></div></div>
<ol class="dp-cpp"><li class="alt"><span class="keyword">typedef</span><span>&nbsp;</span><span class="keyword">struct</span><span>&nbsp;{&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;ngx_recv_pt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;recv;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;ngx_recv_chain_pt&nbsp;&nbsp;recv_chain;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;ngx_recv_pt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;udp_recv;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;ngx_send_pt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;ngx_send_chain_pt&nbsp;&nbsp;send_chain;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;ngx_uint_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flags;&nbsp;&nbsp;</span></li><li class=""><span>}&nbsp;ngx_os_io_t;&nbsp;&nbsp;</span></li></ol></div><textarea class="cpp" style="display: none; background-color: rgb(255,255,255)" name="code" readOnly>typedef struct {
    ngx_recv_pt        recv;
    ngx_recv_chain_pt  recv_chain;
    ngx_recv_pt        udp_recv;
    ngx_send_pt        send;
    ngx_send_chain_pt  send_chain;
    ngx_uint_t         flags;
} ngx_os_io_t;</textarea><br />这里有五个函数指针（*_pt都是函数指针）和一个变量，用于收发网络数据，我把它理解为OO中的abstract class（每个ngx_os_io_t定义的变量都会重新实现这五个函数）。 
<p>&nbsp;</p>
<p>拥有函数指针的struct，我通常认为它们是OO中的abstract class，实现它们的文件（一堆函数）要对应到OO上，我则喜欢把它们当做子类来看。对于void*这样的成员，要根据意图来看了，通常我会转换成聚合加继承的关系。</p>
<p><img alt="" src="http://hi.csdn.net/attachment/201202/1/0_1328087269KWms.gif" /><br /></p>
<p>ngx_io会在相应的ngx_os_specific_init方法中，来策略性的选择到底使用哪个实现。客户代码只需要简单的调用ngx_io中的方法即可。</p>
<p><br /></p>
<p>adapter模式：</p>
<p>这个模式用以适配接口，通常都是我们已经定义好一种接口了，有一个新的实现却有着不同的接口，接下来adapter就开始发力了。下面我们仍然以nginx对网络IO操作的封装部分来看。</p>
<p>linux平台下可能存在普通的IO或者异步IO方式。我们在最初已经封装好ngx_os_io_t接口了，客户代码都是这么直接使用的。现在linux实现了异步IO，而它的调用方式与普通的读写IO接口完全不同，所以，如果要支持aoi就需要一层adapter来适配ngx_os_io_t，这就是adapter方式了。</p>
<p><img alt="" src="http://hi.csdn.net/attachment/201202/1/0_1328087260lL6K.gif" /><br /></p>
<p>上图中，ngx_os_aio适配了原生的异步IO接口，这样，用户代码仍然像以前一样，只要直接使用ngx_io中的五个接口方法，当nginx的IO部分支持linux aio后，用户代码不需要修改。</p>
<p><br /></p>
<p>bridge桥模式：</p>
<p>桥模式用于将抽象和实现分离，各自都能独立的变化。下面以nginx的核心概念module举例，虽然有些牵强，因为nginx的代码从来没这么用过：通常都是一个抽象module context只对应着一个实现module来用，但是，毕竟这种结构下还是可以达到抽象与实现分离的目的，桥模式只好对应到这上面了。</p>
<p>nginx是以module的概念贯穿始终的。它有一个基本的抽象层ngx_core_module_t（从意图上判断，context有抽象接口的功能，虽然简单从语法上看不出）。然后，nginx module有三个基本类型，分别是event（处理各种事件模型，如epoll/select等），http（处理各种http协议的事件），mail（处理mail相关的事件）。针对每种类型的module，都有许多个实现，比如event module就有9个实现，这里的每个实现其实也是个子类。</p>
<p><br /></p>
<p>但是，在我们理解桥模式时，这些子类暂时要被看成是event module的实例。代码中看，像ngx_epoll_module这样的子类中，还是把一些通用的细节隐藏给ngx_event_core_module来做（管理这个词更合适）了。从这个角度可以认为，通过context接口，把三个基本module实现分开了。来看看类图：</p>
<p><img alt="" src="http://hi.csdn.net/attachment/201202/1/0_13280872736utS.gif" /><br /></p>
<p>nginx自己用时，是以ngx_module_t中的type成员来决定使用哪个实现的。目前的nginx代码中，如果用了一种接口就一定会指定相应的type。可是实际上，这也可以用来展示桥模式。以事件module为例来看看：</p>
<p><img alt="" src="http://hi.csdn.net/attachment/201202/1/0_1328087277S56q.gif" /><br /></p>
<p>由于UML本就是针对OO语言的，所以以上我画的类图都比较牵强，什么是继承？什么是聚合？在C语言中，往往都是通过几个函数指针，或者void*指针实现各种封装和多态。没有什么语法上的关联，我就只能从代码意图中来判断了。而代码意图这个比较虚，因为不同的角度理解出来都不一样，所以这个确实不好画。太灵活了点，我只能从一个便于说明的角度来看，例如：上面的ngx_devpoll_module其实就是一个ngx_module_t，呵呵，但是，实际上它最关心的是ngx_event_actions_t的实现，如果完全根据语法来看，根本说不通的。但从代码意图中看，这些module并不关心ngx_module_t，所以我认为，它们只是在实现ngx_event_module_t了。</p>
<p>当然以上只是一家之言，不必当真，如果对nginx源码有研究的话，欢迎各位拍砖。</p>
<p><br /></p>
<p>客观的说，C语言确实在封装上很差，就像nginx，如果我们要开发一个处理http协议的module嵌入进nginx进程，必须了解ngx_http_module里到底做了什么，真没隐藏啥细节，module开发者们表示很郁闷。上面的这些设计模式，只是做到了代码上的解藕。如果nginx用C++写的话，我相信，现在第三方module都能数以万计了。<br /><br /><br />原文地址：<br /><a href="http://blog.csdn.net/russell_tao/article/details/7220237">http://blog.csdn.net/russell_tao/article/details/7220237</a></p> <img src ="http://www.cppblog.com/xuht/aggbug/164797.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xuht/" target="_blank">xuht</a> 2012-02-01 18:01 <a href="http://www.cppblog.com/xuht/archive/2012/02/01/164797.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC2008中影响exe大小和速度的全部编译选项(转)</title><link>http://www.cppblog.com/xuht/archive/2011/10/13/158227.html</link><dc:creator>xuht</dc:creator><author>xuht</author><pubDate>Thu, 13 Oct 2011 08:10:00 GMT</pubDate><guid>http://www.cppblog.com/xuht/archive/2011/10/13/158227.html</guid><wfw:comment>http://www.cppblog.com/xuht/comments/158227.html</wfw:comment><comments>http://www.cppblog.com/xuht/archive/2011/10/13/158227.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xuht/comments/commentRss/158227.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xuht/services/trackbacks/158227.html</trackback:ping><description><![CDATA[&nbsp;我再次强调，完全脱离编程环境的C/C++学习方法，不是好的方法，现在所谓的环境中立理论就是&#8220;什么都不学&#8221;理论，VC、GCC，主流的就两个，精通其中一个就能吃遍天下，教材里就应该选择一个大讲特讲！ <br /><br />&nbsp; &nbsp; 作为VC的代表，今天我给大家介绍VC中的编译器选项，全面介绍不需要，MSDN里从头到尾都介绍完了，今天我只讲对生成的exe文件大小和速度有影响的。 <br /><br />&nbsp; &nbsp; 用VC就得用IDE，我也以IDE的工程设置里面的排列顺序介绍，某些选项需要自己手动添加的最后介绍，我后面说的默认值是release的，debug版本一般不需要调选项。 <br /><br /><strong>项目 - 属性 - 配置属性 - C/C++，这是编译器选项。</strong> <br /><br />优化： <br />&nbsp; &nbsp; <span style="color: #ff0000">通常，算法程序选择最大化速度(/O2)，界面程序选择最小化大小(/O1)，可以获得最佳的效果。 <br />&nbsp; &nbsp; 优选大小或速度，只有在使用完全优化(/Ox)时才有效，完全优化一般不推荐使用，用处就是可以生成速度与/O2基本相当，但是体积更小的代码（选速度优先的话）。</span> <br />&nbsp; &nbsp; 其他几个选项实际上已包含在/O1、/O2之中，具体请看MSDN。 <br /><br />代码生成： <br />&nbsp; &nbsp; 启用字符串池(/GF)，会将相同的字符串合并，当然可以减小空间占用，虽然本项目默认没有打开，但是默认的/Zi选项会自动打开/GF，这里打不打开一样。 <br />&nbsp; &nbsp; 启用C++异常：该项默认打开，在C++项目中（比如MFC中），<span style="color: #ff0000">会大大增加程序体积，增加约30%</span>，关闭并不代表try不能用了，但会一定程度上降低健壮性，对于空间要求较高的程序，建议关闭。对于正式项目，请参见MSDN，看看会不会造成不利影响。 <br />&nbsp; &nbsp; 运行库：默认多线程DLL(/MD)，<span style="color: #ff0000">体积最优的方案</span>，如果对方没有VS运行时库，选择/MT会将C/C++运行库静态编译，体积增加不少，因此，我的选择一般是程序与redist包一起发布，也就几M，而且以后永远可以接受/MD版本了。 <br />&nbsp; &nbsp; 缓冲区安全检查：关闭的话，减少0.5K~1K体积（默认情况，VC的段长度512字节，因此程序体积变化的最小单位是0.5K）。 <br />&nbsp; &nbsp; 启用增强指令集：真想用SSE3的话去用Intel C++，VS2008只支持到SSE2，而且，在我的机器上貌似使用默认设置就能达到选择SSE2的相同速度，<span style="color: #ff0000">如果安装了Intel C++ 11，可集成与VS2008，同样的地方选择SSE3效果超群</span>。 <br />&nbsp; &nbsp; 浮点模型：精确还是快速理论上肯定对速度有影响，但是我极少使用浮点编程，我的方向是系统、安全和密码，都是整数的天下。 <br /><br />高级： <br />&nbsp; &nbsp; 编译为C还是C++影响不大，这充分说明了C++简单面向对象特性和C效率差不多（如重载，默认情况下，编译器会检查扩展名决定目标代码类型，对于cpp文件，所有的函数都会编译为可重载的类型，但是对效率几乎没有影响）。 <br /><br /><strong>项目 - 属性 - 配置属性 - 链接器，这是链接器选项。</strong> <br /><br />输入： <br />&nbsp; &nbsp; 忽略库只有在库冲突时候才有用，VC绝对不会连接没有调用到的库，哪怕你明确指定了。 <br /><br />清单文件： <br />&nbsp; &nbsp; 完全使用API编程可以不生成清单。减少约1K体积。 <br />&nbsp; &nbsp; 一般情况下，关闭UAC的那一项，可减少0.5K。 <br /><br />调试： <br />&nbsp; &nbsp; 关闭&#8220;生成调试信息(/DEBUG)&#8221;，<span style="color: #ff0000">根据程序规模</span>，可减少1K~几十K。 <br /><br />优化： <br />&nbsp; &nbsp; release模式，默认情况下已经该组已经最优了，/OPT:REF和/OPT:ICF已经打开，注意，VS2005、VS2008中Windows 98优化那一项没用，不像VC6取消Windows 98优化可以大大减小体积。因为VS2005、VS2008中段大小已经是512字节，VC6默认4K。 <br /><br />高级： <br />&nbsp; &nbsp; 指定入口点，<span style="color: #ff0000">可以大大减小程序体积</span>，但是不调用CRT的入口无法自动处理参数，可用GetCommandLine和CommandLineToArgvW这两个API来处理参数。 <br />&nbsp; &nbsp; 随机基址：默认模式启用映像随机化(/DYNAMICBASE)，会大大增加程序体积，因为这是个增加程序防反编译、防破解能力的选项。如无需求，请选择禁用映像随机化(/DYNAMICBASE:NO)，<span style="color: #ff0000">文件越大，体积缩小越明显，至少30%</span>。 <br /><br />命令行： <br />&nbsp; &nbsp; 小程序，可以指定段大小/ALIGN，/O1编译的化最小可以使用/ALIGN:4，这个选项不推荐，第一有点规模的程序就不能用太小的段，/O2优化的也不能用小段，而且默认的512字节段可以使用UPX压缩，再小就不能了，除非咱们编译那种600字节的Hello World，这个选项意义不大，因此微软才没有给他一个图形选项。 <br />&nbsp; &nbsp; 同样，编译600字节hello world还需要/merge合并段选项，同样不推荐使用。 <br /><br />&nbsp; &nbsp; 有些选项VS2005和VS2003没有，VS2003还包括几个VS2008废除的选项，实际上VC里面程序优化效率最高的个人感觉是VS2003。VC6的界面差别比较大，选项有一定差异，但毕竟都是微软的产品，差别不大，甚至于MASM这个汇编编译器，连接选项大都与VC相同&#8230;&#8230; <br /><br />&nbsp; &nbsp; 再说一点，VS2008SP1的MFC工程会自动生成巨大的256*256真彩图标，因此默认的MFC对话框程序都有近100K，建议删除多余的图标，配合上述选项能减到10多K<br /><br /><br />原文地址：<a href="http://blog.csdn.net/jackyjkchen/article/details/4676635">http://blog.csdn.net/jackyjkchen/article/details/4676635</a><br /><img src ="http://www.cppblog.com/xuht/aggbug/158227.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xuht/" target="_blank">xuht</a> 2011-10-13 16:10 <a href="http://www.cppblog.com/xuht/archive/2011/10/13/158227.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>