﻿<?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++博客-saga's blog-随笔分类-转的贴</title><link>http://www.cppblog.com/saga/category/1843.html</link><description>学习，钻研，思考，创新！
我才刚上路，有好多的期待！</description><language>zh-cn</language><lastBuildDate>Tue, 20 May 2008 14:46:36 GMT</lastBuildDate><pubDate>Tue, 20 May 2008 14:46:36 GMT</pubDate><ttl>60</ttl><item><title>[解释]“hardcode”是什么意思？</title><link>http://www.cppblog.com/saga/archive/2007/12/22/39281.html</link><dc:creator>saga.constantine</dc:creator><author>saga.constantine</author><pubDate>Sat, 22 Dec 2007 07:47:00 GMT</pubDate><guid>http://www.cppblog.com/saga/archive/2007/12/22/39281.html</guid><wfw:comment>http://www.cppblog.com/saga/comments/39281.html</wfw:comment><comments>http://www.cppblog.com/saga/archive/2007/12/22/39281.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/saga/comments/commentRss/39281.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/saga/services/trackbacks/39281.html</trackback:ping><description><![CDATA[今天看看雪的文章，碰见hardcode一词不懂，查金山2007没有解释。网上找解释如下：<br><br>hardcode----硬编码。<br>所谓硬编码，hardcode，就是把一个本来应该（可以）写到配置信息中的信息直接在程序代码中写死了。 &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 例如，写了一个收发邮件的程序，用户名，密码，服务器地址等最好做成外部配置， &nbsp; <br>&nbsp; 但是如果直接写死在程序代码中，每次改信息时需要重新编译了&#8230;&#8230; &nbsp; <br>&nbsp; &nbsp; <br>&nbsp; 这种程序不好维护。&nbsp;&nbsp;&nbsp;<br>&nbsp; 一般懒的程序员或者初学者这种程序产量较大。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p>在计算机程序或文本编辑中，hardcode(这个词比hard code用起来要频繁一些)是指将可变变量用一个固定值来代替的方法。用这种方法编译后，如果以后需要更改此变量就非常困难了。大部分程序语言里，可以将一个固定数值定义为一个标记，然后用这个特殊标记来取代变量名称。当标记名称改变时，变量名不变，这样，当重新编译整个程序时，所有变量都不再是固定值，这样就更容易的实现了改变变量的目的。尽管通过编辑器的查找替换功能也能实现整个变量名称的替换，但也很有可能出现多换或者少换的情况，而在计算机程序中，任何小错误的出现都是不可饶恕的。最好的方法是单独为变量名划分空间，来实现这种变化，就如同前面说的那样，将需要改变的变量名暂时用一个定义好的标记名称来代替就是一种很好的方法。通常情况下，都应该避免使用hardcode方法。　　
<p>有时也用hardcode来形容那些非常难学的语言，比如C或者C++语言，相对的，用softcode来形容象VB这类简单好用的程序语言。 </p>
<img src ="http://www.cppblog.com/saga/aggbug/39281.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/saga/" target="_blank">saga.constantine</a> 2007-12-22 15:47 <a href="http://www.cppblog.com/saga/archive/2007/12/22/39281.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]windows消息分流器 </title><link>http://www.cppblog.com/saga/archive/2007/09/04/31311.html</link><dc:creator>saga.constantine</dc:creator><author>saga.constantine</author><pubDate>Tue, 04 Sep 2007 05:40:00 GMT</pubDate><guid>http://www.cppblog.com/saga/archive/2007/09/04/31311.html</guid><wfw:comment>http://www.cppblog.com/saga/comments/31311.html</wfw:comment><comments>http://www.cppblog.com/saga/archive/2007/09/04/31311.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/saga/comments/commentRss/31311.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/saga/services/trackbacks/31311.html</trackback:ping><description><![CDATA[**转载**<br>自己看核心编程，对消息分流器不太理解，这篇写的不错，所以转载。<br>文章作者：欣欣<br>原文链接：<a href="http://blog.csdn.net/hopkins9961629/archive/2006/01/25/588184.aspx">http://blog.csdn.net/hopkins9961629/archive/2006/01/25/588184.aspx</a><br><br>
<p style="FONT-SIZE: 12pt">很好理解,windows操作系统使用消息处理机制,那么,我们所设计的程序如何才能分辨和处理系统中的各种消息呢?这就是消息分流器的作用.</p>
<p style="FONT-SIZE: 12pt">简单来说,消息分流器就是一段代码,在我的讲述中,将分7重来循序渐进的介绍它.从最初的第1重到最成熟的第7重,它的样子会有很大的变化.但,实现的功能都是一样的,所不同的,仅仅是变得更加简练罢了.</p>
<p style="FONT-SIZE: 12pt">程序开始时候,会是main函数,然后会生成初始的窗口,同时会调用WndProc函数.这是一个自定义的函数,名字也会有变化,但其功能是一样的,就是运行消息分流器.WndProc函数如下:</p>
<p style="FONT-SIZE: 12pt">LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,WPARAM wParam, LPARAM lParam)<br>{</p>
<p style="FONT-SIZE: 12pt">//......</p>
<p style="FONT-SIZE: 12pt">return DefWindowProc(hwnd, msg, wParam, lParam);</p>
<p style="FONT-SIZE: 12pt">}</p>
<p style="FONT-SIZE: 12pt">这其中,hwnd是窗口的句柄,msg是系统发送来的消息的名字.wParam和lParam则是随消息一起发送来的消息参数.</p>
<p style="FONT-SIZE: 12pt">WndProc函数使用了消息分流器，下面把消息分流器的内容解释一下：</p>
<p style="FONT-SIZE: 12pt">一重，当不同的消息出现时，在其中写入相应的程序语句即可。<br>LRESULT CALLBACK WndProc (HWND hwnd, UINT msg,WPARAM wParam, LPARAM lParam)<br>{<br>&nbsp;switch(msg)<br>&nbsp;{<br>&nbsp;&nbsp;case WM_CREATE:<br>&nbsp;&nbsp;// ...<br>&nbsp;&nbsp;return 0;</p>
<p style="FONT-SIZE: 12pt">&nbsp;&nbsp;case WM_PAINT:<br>&nbsp;&nbsp;// ...<br>&nbsp;&nbsp;return 0;</p>
<p style="FONT-SIZE: 12pt">&nbsp;&nbsp;case WM_DESTROY:<br>&nbsp;&nbsp;//...<br>&nbsp;&nbsp;return 0;<br>&nbsp;}<br>&nbsp;return DefWindowProc(hwnd, msg, wParam, lParam);<br>}</p>
<p style="FONT-SIZE: 12pt">二重，运用三个消息分流器进行处理。<br>LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)<br>{<br>&nbsp;switch(msg)<br>&nbsp;{<br>&nbsp;&nbsp;case WM_CREATE:<br>&nbsp;&nbsp;return HANDLE_WM_CREATE(hwnd, wParam, lParam, Cls_OnCreate);</p>
<p style="FONT-SIZE: 12pt">&nbsp;&nbsp;case WM_PAINT:<br>&nbsp;&nbsp;return HANDLE_WM_PAINT(hwnd, wParam, lParam, Cls_OnPaint);</p>
<p style="FONT-SIZE: 12pt">&nbsp;&nbsp;case WM_DESTROY:<br>&nbsp;&nbsp;return HANDLE_WM_DESTROY(hwnd, wParam, lParam, Cls_OnDestroy);<br>&nbsp;}<br>&nbsp;return DefWindowProc(hwnd, msg, wParam, lParam);<br>}<br>这里的HANDLE_WM_CREATE，HANDLE_WM_PAINT，HANDLE_WM_DESTROY就是消息分流器。<br>与消息不同之处就是在前面增加了&#8220;HANDLE_&#8221;字符，windows的消息分流器就是这样的模样。<br>它的本质就是宏定义。<br>其中的四个参数有三个都是从本函数的入口参数中直接得到的，即为hwnd, wParam, lParam。<br>只有第四的参数是表明调用的函数。<br>消息分流器是在winowsx.h文件中定义的。由此，可以看出第四个参数是调用的函数，其定义如下：</p>
<p style="FONT-SIZE: 12pt">#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) ((fn)((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L)</p>
<p style="FONT-SIZE: 12pt">#define HANDLE_WM_PAINT(hwnd, wParam, lParam, fn) ((fn)(hwnd), 0L)</p>
<p style="FONT-SIZE: 12pt">#define HANDLE_WM_DESTROYCLIPBOARD(hwnd, wParam, lParam, fn) ((fn)(hwnd), 0L)</p>
<p style="FONT-SIZE: 12pt">0L是表示int类型的变量，其数值为0。<br>int类型时，可在后面加l或者L(小写和大写形式)<br>表明无符号数时，可在后面加u或者U(小写和大写形式)<br>float类型时，可在后面加f或者F(小写和大写形式)<br>例如：<br>128u 1024UL 1L 8Lu 3.14159F 0.1f </p>
<p style="FONT-SIZE: 12pt">LRESULT是一个系统的数据类型，其定义如下：<br>typedef LONG_PTR LRESULT;</p>
<p style="FONT-SIZE: 12pt">LONG_PTR也是一个系统的数据类型，其定义如下：<br>#if defined(_WIN64)<br>&nbsp;typedef __int64 LONG_PTR; <br>#else<br>&nbsp;typedef long LONG_PTR;<br>#endif<br>由此可见，LRESULT的实质就是64的long类型的变量</p>
<p style="FONT-SIZE: 12pt">那么(LRESULT)-1L的实质并不是减法，而是((LRESULT)(-1L))，即强制类型转换</p>
<p style="FONT-SIZE: 12pt">三重，把消息分流器的宏定义代换回去，就成了下面的样子<br>LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)<br>{<br>&nbsp;switch(msg)<br>&nbsp;{<br>&nbsp;&nbsp;case WM_CREATE:<br>&nbsp;&nbsp;return Cls_OnCreate(hwnd, (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L;<br>&nbsp;&nbsp;// 如果处理了消息，则Cls_OnCreate应返回TRUE，导致WndProc返回0，否则Cls_OnCreate返回FALSE，导致WndProc返回-1；</p>
<p style="FONT-SIZE: 12pt">&nbsp;&nbsp;case WM_PAINT:<br>&nbsp;&nbsp;return Cls_OnPaint(hwnd), 0L;<br>&nbsp;&nbsp;// 逗号表达式；Cls_OnPaint是void类型，这里返回0； </p>
<p style="FONT-SIZE: 12pt">&nbsp;&nbsp;case WM_DESTROY:<br>&nbsp;&nbsp;return Cls_OnDestroy(hwnd), 0L; // 同Cls_OnPaint<br>&nbsp;} <br>&nbsp;return DefWindowProc(hwnd, msg, wParam, lParam);<br>}<br>在逗号表达式，C++会计算每个表达式，但完整的逗号表达式的结果是最右边表达式的值。<br>所以，会return 0。<br>然后，就可以手动的编写各个处理函数了：Cls_OnCreate，Cls_OnPaint，WM_DESTROY。</p>
<p style="FONT-SIZE: 12pt">四重，<br>LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)<br>{<br>&nbsp;switch(msg)<br>&nbsp;{<br>&nbsp;&nbsp;HANDLE_MSG(hwnd, WM_CREATE, Cls_OnCreate);<br>&nbsp;&nbsp;HANDLE_MSG(hwnd, WM_PAINT, Cls_OnPaint);<br>&nbsp;&nbsp;HANDLE_MSG(hwnd, WM_DESTROY, Cls_OnDestroy);<br>&nbsp;}<br>&nbsp;return DefWindowProc(hwnd, msg, wParam, lParam);<br>}</p>
<p style="FONT-SIZE: 12pt">HANDLE_MSG也是一个宏，它在windowsx.h中定义，如下：<br>#define HANDLE_MSG(hwnd, message, fn) case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))</p>
<p style="FONT-SIZE: 12pt">这个宏要做的就是根据不同的message（##用来连接前后的字符串），把自己&#8220;变成&#8221;相应的HANDLE_XXXXMESSAGE形式的宏，再通过相应的宏来执行消息处理代码。<br>说白了，就是把message的消息做为替换，##就是一个替换的标志。<br>如果没有##，就成了HANDLE_message了，这样，宏是不会被代换的。<br>如果就单独一个，则会代换，如hwnd和fn。</p>
<p style="FONT-SIZE: 12pt">比如实际代码中写入：<br>HANDLE_MSG(hwnd, WM_CREATE, Cls_OnCreate)<br>则经过转换就变成：<br>case (WM_CREATE): return HANDLE_WM_CREATE((hwnd), (wParam), (lParam), (Cls_OnCreate))<br>这与二重一模一样。</p>
<p style="FONT-SIZE: 12pt">以上四重，是消息分离器的基本使用，但，这不完整，消息分离器主要应用在对话框消息处理中。<br>这里，窗口子类化是我们经常使用的手段，这也可以通过消息分流器实现，</p>
<p style="FONT-SIZE: 12pt">第五重<br>LRESULT CALLBACK Dlg_Proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)<br>{<br>&nbsp;switch(msg)<br>&nbsp;{<br>&nbsp;&nbsp;HANDLE_MSG(hwnd, WM_INITDIALO , Cls_OnInitDialog); // 不能直接使用HANDLE_MSG宏<br>&nbsp;&nbsp;HANDLE_MSG(hwnd, WM_COMMAND, Cls_OnCommand); // 不能直接使用HANDLE_MSG宏<br>&nbsp;}<br>&nbsp;return false;<br>} <br>由于是窗口子类化，所以，最后，返回的是false，以表明，如果没有约定响应的消息，<br>则返回父亲窗口false，如果有，则返回ture，这是与前四重不同的地方。<br>一般情况下，对话框过程函数应该在处理了消息的情况下返回TRUE，如果没有处理，则返回FALSE。<br>如果对话框过程返回了FALSE，那么对话框管理器为这条消息准备默认的对话操作。</p>
<p style="FONT-SIZE: 12pt">但是，这其中有错误，因为有的消息,需要单独处理。单独处理的消息列表见SetDlgMsgResult宏。</p>
<p style="FONT-SIZE: 12pt">第六重<br>这点小问题，这就需要用到SetDlgMsgResult(hwnd, msg, result)宏。 </p>
<p style="FONT-SIZE: 12pt">LRESULT CALLBACK Dlg_Proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)<br>{<br>switch(msg)<br>&nbsp;{<br>&nbsp;case WM_INITDIALO:<br>&nbsp;return (SetDlgMsgResult(hwnd, Msg, HANDLE_WM_INITDIALO((hwnd), (wParam), (lParam), (fn)));</p>
<p style="FONT-SIZE: 12pt">&nbsp;case WM_COMMAND:<br>&nbsp;return (SetDlgMsgResult(hwnd, Msg, HANDLE_WM_COMMAND((hwnd), (wParam), (lParam), (fn)));<br>&nbsp;}<br>return false;<br>} <br>这里，就用直接用到了第二重的消息分流器，而抛弃了其他。</p>
<p style="FONT-SIZE: 12pt">这个宏定义如下：<br>#define SetDlgMsgResult(hwnd, msg, result) <br>(<br>&nbsp;( <br>&nbsp;(msg) == WM_CTLCOLORMSGBOX || <br>&nbsp;(msg) == WM_CTLCOLOREDIT || <br>&nbsp;(msg) == WM_CTLCOLORLISTBOX || <br>&nbsp;(msg) == WM_CTLCOLORBTN || <br>&nbsp;(msg) == WM_CTLCOLORDLG || <br>&nbsp;(msg) == WM_CTLCOLORSCROLLBAR || <br>&nbsp;(msg) == WM_CTLCOLORSTATIC || <br>&nbsp;(msg) == WM_COMPAREITEM || <br>&nbsp;(msg) == WM_VKEYTOITEM || <br>&nbsp;(msg) == WM_CHARTOITEM || <br>&nbsp;(msg) == WM_QUERYDRAGICON || <br>&nbsp;(msg) == WM_INITDIALOG <br>&nbsp;) ? <br>&nbsp;(BOOL)(result) : <br>&nbsp;(SetWindowLongPtr((hwnd), DWLP_MSGRESULT, (LPARAM)(LRESULT)(result)), TRUE)<br>)</p>
<p style="FONT-SIZE: 12pt">为了表述清楚，所以用了此格式，这是一个三项表达式，首先对消息类型进行考察。</p>
<p style="FONT-SIZE: 12pt">如果对话框过程处理的消息恰巧为返回特定值中的一个，则如实返回result；<br>不要被前面的BOOL蒙蔽，BOOL在头文件中的定义实际上是一个int型，<br>一旦需要返回非TRUE或FALSE的其他值，照样可以；</p>
<p style="FONT-SIZE: 12pt">这样，我们的Cls_OnInitDialog就能够正确的返回它的BOOL值了，<br>而Cls_OnCommand在处理之后，也可以由后面的逗号表达式正确的返回一个TRUE表示消息已处理。</p>
<p style="FONT-SIZE: 12pt">第七重<br>我们还可以把case也包含进来，就成了如下的样子。</p>
<p style="FONT-SIZE: 12pt">LRESULT CALLBACK Dlg_Proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)<br>{<br>&nbsp;switch(msg)<br>&nbsp;{<br>&nbsp;chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Cls_OnInitDialog); <br>&nbsp;chHANDLE_DLGMSG(hwnd, WM_COMMAND, Cls_OnCommand); <br>&nbsp;}<br>&nbsp;return false;<br>}</p>
<p style="FONT-SIZE: 12pt">chHANDLE_DLGMSG是牛人定义的一个宏，它把case也包含进来了。<br>#define chHANDLE_DLGMSG(hwnd, message, fn) case (message): return (SetDlgMsgResult(hwnd, uMsg, HANDLE_##message((hwnd), (wParam), (lParam), (fn)))) </p>
<p style="FONT-SIZE: 12pt">这样，程序中的语句<br>&nbsp;switch (uMsg) <br>&nbsp;{<br>&nbsp;&nbsp;chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);<br>&nbsp;&nbsp;chHANDLE_DLGMSG(hwnd, WM_SIZE,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dlg_OnSize);<br>&nbsp;&nbsp;chHANDLE_DLGMSG(hwnd, WM_COMMAND,&nbsp;&nbsp;&nbsp; Dlg_OnCommand);<br>&nbsp;}</p>
<p style="FONT-SIZE: 12pt">就被翻译成：<br>&nbsp;switch (uMsg)<br>&nbsp;{<br>&nbsp;case (WM_INITDIALOG):<br>&nbsp;&nbsp;return (SetDlgMsgResult(hwnd, uMsg, HANDLE_WM_INITDIALOG((hwnd), (wParam), (lParam), (Dlg_OnInitDialog))));</p>
<p style="FONT-SIZE: 12pt">&nbsp;case (WM_SIZE)<br>&nbsp;&nbsp;return (SetDlgMsgResult(hwnd, uMsg, HANDLE_WM_SIZE((hwnd), (wParam), (lParam), (Dlg_OnSize))));</p>
<p style="FONT-SIZE: 12pt">&nbsp;case (WM_COMMAND)<br>&nbsp;&nbsp;return (SetDlgMsgResult(hwnd, uMsg, HANDLE_WM_COMMAND((hwnd), (wParam), (lParam), (Dlg_OnCommand))));<br>&nbsp;}<br></p>
<p style="FONT-SIZE: 12pt">这样,消息分流器,就介绍完毕.</p>
<img src ="http://www.cppblog.com/saga/aggbug/31311.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/saga/" target="_blank">saga.constantine</a> 2007-09-04 13:40 <a href="http://www.cppblog.com/saga/archive/2007/09/04/31311.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转帖]fstream的使用方法介绍</title><link>http://www.cppblog.com/saga/archive/2007/06/19/26652.html</link><dc:creator>saga.constantine</dc:creator><author>saga.constantine</author><pubDate>Tue, 19 Jun 2007 15:46:00 GMT</pubDate><guid>http://www.cppblog.com/saga/archive/2007/06/19/26652.html</guid><wfw:comment>http://www.cppblog.com/saga/comments/26652.html</wfw:comment><comments>http://www.cppblog.com/saga/archive/2007/06/19/26652.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/saga/comments/commentRss/26652.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/saga/services/trackbacks/26652.html</trackback:ping><description><![CDATA[<p>在C++中，有一个stream这个类，所有的I/O都以这个&#8220;流&#8221;类为基础的，包括我们要认识的文件I/O，stream这个类有两个重要的运算符：</p>
<p>1、插入器(&lt;&lt;)<br>　　向流输出数据。比如说系统有一个默认的标准输出流(cout)，一般情况下就是指的显示器，所以，cout&lt;&lt;"Write Stdout"&lt;&lt;' ';就表示把字符串"Write Stdout"和换行字符(' ')输出到标准输出流。</p>
<p>2、析取器(&gt;&gt;)<br>　　从流中输入数据。比如说系统有一个默认的标准输入流(cin)，一般情况下就是指的键盘，所以，cin&gt;&gt;x;就表示从标准输入流中<a name=1></a><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">读取</strong>一个指定类型(即变量x的类型)的数据。</p>
<p>　　在C++中，对文件的操作是通过stream的子类<a name=0></a><strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">fstream</strong>(file stream)来实现的，所以，要用这种方式操作文件，就必须加入头文件<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">fstream</strong>.h。下面就把此类的文件操作过程一一道来。</p>
<p>一、打开文件<br>　　在<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">fstream</strong>类中，有一个成员函数open()，就是用来打开文件的，其原型是：</p>
<p>void open(const char* filename,int mode,int access);</p>
<p>参数：</p>
<p>filename：　　要打开的文件名 <br>mode：　　　　要打开文件的方式 <br>access：　　　打开文件的属性<br>打开文件的方式在类ios(是所有流式I/O类的基类)中定义，常用的值如下： </p>
<p>ios::app：　　　以追加的方式打开文件 <br>ios::ate：　　　文件打开后定位到文件尾，ios:app就包含有此属性 <br>ios::binary： 　以<a name=2></a><strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">二进制</strong>方式打开文件，缺省的方式是文本方式。两种方式的区别见前文 <br>ios::in：　　　 文件以输入方式打开 <br>ios::out：　　　文件以输出方式打开 <br>ios::nocreate： 不建立文件，所以文件不存在时打开失败　 <br>ios::noreplace：不覆盖文件，所以打开文件时如果文件存在失败 <br>ios::trunc：　　如果文件存在，把文件长度设为0 <br>　　可以用&#8220;或&#8221;把以上属性连接起来，如ios::out|ios::binary</p>
<p>　　打开文件的属性取值是：</p>
<p>0：普通文件，打开访问 <br>1：只读文件 <br>2：隐含文件 <br>4：系统文件 <br>　　可以用&#8220;或&#8221;或者&#8220;+&#8221;把以上属性连接起来 ，如3或1|2就是以只读和隐含属性打开文件。</p>
<p>　　例如：以<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">二进制</strong>输入方式打开文件c:config.sys </p>
<p>　　<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">fstream</strong> file1;<br>　　file1.open("c:\config.sys",ios::binary|ios::in,0);</p>
<p>　　如果open函数只有文件名一个参数，则是以读/写普通文件打开，即：</p>
<p>　　file1.open("c:\config.sys");&lt;=&gt;file1.open("c:\config.sys",ios::in|ios::out,0);</p>
<p>　　另外，<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">fstream</strong>还有和open()一样的构造函数，对于上例，在定义的时侯就可以打开文件了：</p>
<p>　　<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">fstream</strong> file1("c:\config.sys");</p>
<p>　　特别提出的是，<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">fstream</strong>有两个子类：ifstream(input file stream)和ofstream(outpu file stream)，ifstream默认以输入方式打开文件，而ofstream默认以输出方式打开文件。</p>
<p>　　ifstream file2("c:\pdos.def");//以输入方式打开文件<br>　　ofstream file3("c:\x.123");//以输出方式打开文件</p>
<p>　　所以，在实际应用中，根据需要的不同，选择不同的类来定义：如果想以输入方式打开，就用ifstream来定义；如果想以输出方式打开，就用ofstream来定义；如果想以输入/输出方式来打开，就用<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">fstream</strong>来定义。</p>
<p>二、关闭文件<br>　　打开的文件使用完成后一定要关闭，<strong style="COLOR: black; BACKGROUND-COLOR: #ffff66">fstream</strong>提供了成员函数close()来完成此操作，如：file1.close();就把file1相连的文件关闭。</p>
<p>三、读写文件<br>　　读写文件分为文本文件和<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">二进制</strong>文件的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">读取</strong>，对于文本文件的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">读取</strong>比较简单，用插入器和析取器就可以了；而对于<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">二进制</strong>的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">读取</strong>就要复杂些，下要就详细的介绍这两种方式</p>
<p>　　1、文本文件的读写<br>　　文本文件的读写很简单：用插入器(&lt;&lt;)向文件输出；用析取器(&gt;&gt;)从文件输入。假设file1是以输入方式打开，file2以输出打开。示例如下：</p>
<p>　　file2&lt;&lt;"I Love You";//向文件写入字符串"I Love You"<br>　　int i;<br>　　file1&gt;&gt;i;//从文件输入一个整数值。 </p>
<p>　　这种方式还有一种简单的格式化能力，比如可以指定输出为16进制等等，具体的格式有以下一些</p>
<p>操纵符 功能 输入/输出 <br>dec 格式化为十进制数值数据 输入和输出 <br>endl 输出一个换行符并刷新此流 输出 <br>ends 输出一个空字符 输出 <br>hex 格式化为十六进制数值数据 输入和输出 <br>oct 格式化为八进制数值数据 输入和输出 <br>setpxecision(int p) 设置浮点数的精度位数 输出 </p>
<p>　　比如要把123当作十六进制输出：file1&lt; </p>
<p>　　2、<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">二进制</strong>文件的读写<br>①put()<br>　　put()函数向流写入一个字符，其原型是ofstream &amp;put(char ch)，使用也比较简单，如file1.put('c');就是向流写一个字符'c'。 </p>
<p>②get()<br>　　get()函数比较灵活，有3种常用的重载形式：</p>
<p>　　一种就是和put()对应的形式：ifstream &amp;get(char &amp;ch);功能是从流中<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">读取</strong>一个字符，结果保存在引用ch中，如果到文件尾，返回空字符。如file2.get(x);表示从文件中<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">读取</strong>一个字符，并把<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">读取</strong>的字符保存在x中。</p>
<p>　　另一种重载形式的原型是： int get();这种形式是从流中返回一个字符，如果到达文件尾，返回EOF，如x=file2.get();和上例功能是一样的。</p>
<p>　　还有一种形式的原型是：ifstream &amp;get(char *buf,int num,char delim=' ')；这种形式把字符读入由 buf 指向的数组，直到读入了 num 个字符或遇到了由 delim 指定的字符，如果没使用 delim 这个参数，将使用缺省值换行符' '。例如：</p>
<p>　　file2.get(str1,127,'A');//从文件中<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">读取</strong>字符到字符串str1，当遇到字符'A'或<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">读取</strong>了127个字符时终止。</p>
<p>③读写数据块<br>　　要读写<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">二进制</strong>数据块，使用成员函数read()和write()成员函数，它们原型如下：</p>
<p>　　　　read(unsigned char *buf,int num);<br>　　　　write(const unsigned char *buf,int num);</p>
<p>　　read()从文件中<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">读取</strong> num 个字符到 buf 指向的缓存中，如果在还未读入 num 个字符时就到了文件尾，可以用成员函数 int gcount();来取得实际<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">读取</strong>的字符数；而 write() 从buf 指向的缓存写 num 个字符到文件中，值得注意的是缓存的类型是 unsigned char *，有时可能需要类型转换。</p>
<p>例：</p>
<p>　　　　unsigned char str1[]="I Love You";<br>　　　　int n[5];<br>　　　　ifstream in("xxx.xxx");<br>　　　　ofstream out("yyy.yyy");<br>　　　　out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中<br>　　　　in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">读取</strong>指定个整数，注意类型转换<br>　　　　in.close();out.close(); </p>
<p>四、检测EOF<br>　　成员函数eof()用来检测是否到达文件尾，如果到达文件尾返回非0值，否则返回0。原型是int eof();</p>
<p>例：　　if(in.eof())ShowMessage("已经到达文件尾！");</p>
<p>五、文件定位<br>　　和C的文件操作方式不同的是，C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针，它说明输入操作在文件中的位置；另一个是写指针，它下次写操作的位置。每次执行输入或输出时，相应的指针自动变化。所以，C++的文件定位分为读位置和写位置的定位，对应的成员函数是 seekg()和 seekp()，seekg()是设置读位置，seekp是设置写位置。它们最通用的形式如下：</p>
<p>　　　　istream &amp;seekg(streamoff offset,seek_dir origin);<br>　　　　ostream &amp;seekp(streamoff offset,seek_dir origin); </p>
<p>　　streamoff定义于 iostream.h 中，定义有偏移量 offset 所能取得的最大值，seek_dir 表示移动的基准位置，是一个有以下值的枚举： </p>
<p>ios::beg：　　文件开头 <br>ios::cur：　　文件当前位置 <br>ios::end：　　文件结尾 <br>　　这两个函数一般用于<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">二进制</strong>文件，因为文本文件会因为系统对字符的解释而可能与预想的值不同。</p>
<p>例：</p>
<p>　　　　 file1.seekg(1234,ios::cur);//把文件的读指针从当前位置向后移1234个字节<br>　　　　 file2.seekp(1234,ios::beg);//把文件的写指针从文件开头向后移1234个字节 </p>
<img src ="http://www.cppblog.com/saga/aggbug/26652.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/saga/" target="_blank">saga.constantine</a> 2007-06-19 23:46 <a href="http://www.cppblog.com/saga/archive/2007/06/19/26652.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转贴]什么叫0day漏洞？</title><link>http://www.cppblog.com/saga/archive/2007/05/20/24438.html</link><dc:creator>saga.constantine</dc:creator><author>saga.constantine</author><pubDate>Sun, 20 May 2007 07:20:00 GMT</pubDate><guid>http://www.cppblog.com/saga/archive/2007/05/20/24438.html</guid><wfw:comment>http://www.cppblog.com/saga/comments/24438.html</wfw:comment><comments>http://www.cppblog.com/saga/archive/2007/05/20/24438.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/saga/comments/commentRss/24438.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/saga/services/trackbacks/24438.html</trackback:ping><description><![CDATA[眼下的0Day正引发信息安全新&#8220;地震&#8221;看不见的才是最可怕的<br>　　这就是0Day的真正威胁<br>　　如果你是一家企业的网络安全主管，企业外网的安全代码、脚本分析、环境配置、维护补丁已做到无懈可击，内网防火墙、防病毒、入侵检测、身份认证等硬件设施也齐全完备，从技术手段来讲，似乎没有什么可担心的；但你考虑过你所使用的操作系统、网站平台或其他第三方应用程序，是否存在着某个不为人知的重大漏洞呢？当你发现你的网络已遭入侵，信息已被窃取，查遍所有漏洞数据库和安全补丁资料却不得其解。这时，你考虑过0Day么？<br>　　什么是0Day<br>　　0Day的概念最早用于软件和游戏破解，属于非盈利性和非商业化的组织行为，其基本内涵是&#8220;即时性&#8221;。Warez被许多人误认为是一个最大的软件破解组织，而实际上，Warez如黑客一样，只是一种行为。0Day也是。当时的0Day是指在正版软件或游戏发布的当天甚至之前，发布附带着序列号或者解密器的破解版，让使用者可以不用付费就能长期使用。因此，虽然Warez和0Dday都是反盗版的重要打击对象，却同时受到免费使用者和业内同行的推崇。尽管Warez和0Day的拥护者对以此而谋利的盗版商不齿，但商业利益的驱动还是将破解行为的商业化推到了高峰。而眼下的0Day，正在对信息安全产生越来越严重的威胁。<br>　　信息安全意义上的0Day是指在安全补丁发布前而被了解和掌握的漏洞信息。<br>　　2005年12月8日，几乎影响Windows所有操作系统的WMF漏洞在网上公开，虽然微软在8天后提前发布了安全补丁（微软的惯例是在每月的第一个周二），但就在这8天内出现了二百多个利用此漏洞的攻击脚本。漏洞信息的公开加速了软件生产企业的安全补丁更新进程，减少了恶意程序的危害程度。但如果是不公开的0Day呢？WMF漏洞公开之前，又有多少人已经利用了它？是否有很多0Day一直在秘密流传？例如，给全球网络带来巨大危害的&#8220;冲击波&#8221;和&#8220;震荡波&#8221;这两种病毒，如果它们的漏洞信息没有公开，自然也就没有这两种超级病毒的产生。反过来想，有什么理由认为眼下不存在类似的有着重大安全隐患的漏洞呢？（Dtlogin远程溢出漏洞于2002年被发现，2004年公布。）<br>　　看不见的才是最可怕的，这就是0Day的真正威胁。<br>　　不可避免的0Day<br>　　信息价值的飞速提升，互联网在全球的普及，数字经济的广泛应用，这一切都刺激着信息安全市场的不断扩大，软件破解、口令解密、间谍软件、木马病毒全部都从早期的仅做研究和向他人炫耀的目的转化为纯商业利益的运作，并迅速地传播开来，从操作系统到数据库，从应用软件到第三方程序和插件，再到遍布全球的漏洞发布中心，看看它们当中有多少0Day存在？可以毫不夸张的说，在安全补丁程序发布之前，所有的漏洞信息都是0Day，但是从未发布过安全补丁的软件是否就意味着它们当中不存在0Day呢？<br>　　有人说：&#8220;每一个稍具规模的应用软件都可能存在0Day。&#8221;没错！从理论上讲，漏洞必定存在，只是尚未发现，而弥补措施永远滞后而已。<br>　　只要用户方不独自开发操作系统或应用程序，或者说只要使用第三方的软件，0Day的出现就是迟早的事，无论你是使用数据库还是网站管理平台，无论你是使用媒体播放器还是绘图工具，即便是专职安全防护的软件程序本身，都会出现安全漏洞，这已是不争的事实，但最可怕的不是漏洞存在的先天性，而是0Day的不可预知性。<br>　　从开源的角度上来说，Linux更容易比封闭源代码的Windows存在更多的0Day。那些自以为使用着安全操作系统的人，迟早会被0Day攻击弄得哑口无言。而微软呢？远有IIS和IE，近有WMF和Excel，由于其操作系统应用的广泛性，如今已是补丁加补丁，更新再更新，最新操作系统Vista竟然含有几万行的问题代码。尚未发行，已是满目疮痍，谁又能保证微软的源代码没有丝毫泄露呢？<br>　　0Day走向何方<br>　　越来越多的破解者和黑客们，已经把目光从率先发布漏洞信息的荣誉感转变到利用这些漏洞而得到的经济利益上，互联网到处充斥着数以万计的充满入侵激情的脚本小子，更不用说那些以窃取信息为职业的商业间谍和情报人员了。于是，0Day有了市场。<br>　　国外两年前就有了0Day的网上交易，黑客们通过网上报价出售手中未公开的漏洞信息，一个操作系统或数据库的远程溢出源码可以卖到上千美元甚至更高；而国内的黑客同行，前不久也在网上建立了一个专门出售入侵程序号称中国第一0Day的网站，尽管类似的提供黑客工具的网站很多，但此网站与其它网站的区别在于0Day的特性十分明显：价格较高的攻击程序的攻击对象，还没有相应的安全补丁，也就是说这样的攻击程序很可能具有一击必中的效果。这个网站成立不久便在搜索引擎中消失了，也许已经关闭，也许转入地下。但不管怎样，0Day带来的潜在经济利益不可抹杀，而其将来对信息安全的影响以及危害也绝不能轻视。<br>　　软件上的0Day几乎不可避免，那硬件呢？硬件是否存在0Day？答案无疑是肯定的。近年来，思科路由器漏洞频繁出现，今年2月，已被曝光的某知名网络产品漏洞至今仍未被修复。对于那些基于IP协议连接网络的路由、网关、交换机，哪个电信运营商敢百分之百地 保证自己的网络设备万无一失？（2005年4月11日，全国超过二十个城市的互联网出现群发性故障；同年7月12日，北京20万ADSL用户断网）。<br>　　早在两年前，英特尔的首席技术官就提出过互联网不能承受与日俱增的使用者这一想法，当时，被很多人认为是无稽之谈。今年6月，在美国的商业圆桌会议上，包括惠普公司、IBM公司、Sun公司、通用汽车公司、家得宝公司和可口可乐公司等在内的160个企业代表呼吁政府要对发生大规模网络故障的可能性做好准备工作&#8230;&#8230;<br>　　当今的互联网，病毒、蠕虫、僵尸网络、间谍软件、DDoS犹如洪水般泛滥，所有的这一切都或多或少地从0Day走过，可以预测，在不远的将来，互联网瘫痪绝不遥远。<br>　　那么政府管理者、电信运营商、安全厂商，还有全世界的互联网用户，面对0Day，我们准备好了吗？
 <img src ="http://www.cppblog.com/saga/aggbug/24438.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/saga/" target="_blank">saga.constantine</a> 2007-05-20 15:20 <a href="http://www.cppblog.com/saga/archive/2007/05/20/24438.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]用户层下拦截系统api的原理与实现</title><link>http://www.cppblog.com/saga/archive/2007/01/22/17891.html</link><dc:creator>saga.constantine</dc:creator><author>saga.constantine</author><pubDate>Mon, 22 Jan 2007 08:49:00 GMT</pubDate><guid>http://www.cppblog.com/saga/archive/2007/01/22/17891.html</guid><wfw:comment>http://www.cppblog.com/saga/comments/17891.html</wfw:comment><comments>http://www.cppblog.com/saga/archive/2007/01/22/17891.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/saga/comments/commentRss/17891.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/saga/services/trackbacks/17891.html</trackback:ping><description><![CDATA[
		<strong>**<font color="#ff0000">转载</font><font color="#000000">**</font><br />**我自己看了看这片文章，还不错！程序也可以编译出来**<br /><br /></strong>
		<span class="tpc_content">
				<font size="2">文章作者：kiki<br />信息来源：邪恶八进制信息安全团队（</font>
				<a href="http://www.eviloctal.com/" target="_blank">
						<font size="2">www.eviloctal.com</font>
				</a>
				<font size="2">）<br />本文章首发</font>
				<a href="http://www.thysea.com/lb/cgi-bin/leobbs.cgi" target="_blank">
						<font color="royalblue" size="2">黑色海岸线网络安全技术论坛</font>
				</a>
				<font size="2">，后由kiki友情提交到邪恶八进制信息安全团队<br /><br />         拦截api的技术有很多种，大体分为用户层和内核层的拦截．这里只说说用户层的拦截．而用户层也分为许多种：修改PE文件导入表，直接修改要拦截的api的内存（从开始到最后，使程序跳转到指定的地址执行）．不过大部分原理都是修改程序流程，使之跳转到你要执行的地方，然后再返回到原地址．原来api的功能必须还能实现．否则拦截就失去作用了．修改文件导入表的方法的缺点是如果用户程序动态加载（使用LoadLibrary和GetProcAddress函数），拦截将变得复杂一些．所以这里介绍一下第二种方法，直接修改api，当然不是全局的．（后面会说到）<br /><br />　　需要了解的一些知识：<br /><br />　　１．windows内存的结构属性和进程地址空间<br /><br />　　２．函数堆栈的一些知识<br /><br /><br /><br />一：win2000和xp的内存结构和进程地址空间<br /><br />  windows采用4GB平坦虚拟地址空间的做法。即每个进程单独拥有4GB的地址空间。每个进程只能访问自己的这4GB的虚拟空间，而对于其他进程的地址空间则是不可见的。这样保证了进程的安全性和稳定性。但是，这4GB的空间是一个虚拟空间，在使用之前，我们必须先保留一段虚拟地址，然后再为这段虚拟地址提交物理存储器。可是我们的内存大部分都还没有1GB，那么这4GB的地址空间是如何实现的呢？事实上windows采用的内存映射这种方法，即把物理磁盘当作内存来使用，比如我们打开一个可执行文件的时候，操作系统会为我们开辟这个4GB的地址空间：0x00000000--0xffffffff。其中0x00000000--0x7fffffff是属于用户层的空间.0x80000000--0xffffffff则属于共享内核方式分区，主要是操作系统的线程调度，内存管理，文件系统支持，网络支持和所有设备驱动程序。对于用户层的进程，这些地址空间是不可访问的。任何访问都将导致一个错误。开辟这4GB的虚拟地址空间之后，系统会把磁盘上的执行文件映射到进程的地址空间中去(一般是在地址0x00400000，可以通过修改编译选项来修改这个地址)而一个进程运行所需要的动态库文件则一般从0x10000000开始加载。但是如果所有的动态库都加载到这个位置肯定会引起冲突。因此必须对一些可能引起冲突的dll编译时重新修改基地址。但是对于所有的操作系统所提供的动态库windows已经定义好了映射在指定的位置。这个位置会随着版本的不同而会有所改变，不过对于同一台机器上的映射地址来说都是一样的。即在a进程里映射的kernel32.dll的地址和在进程b里的kernel32.dll的地址是一样的。对于文件映射是一种特殊的方式，使得程序不需要进行磁盘i/o就能对磁盘文件进行操作，而且支持多种保护属性。对于一个被映射的文件，主要是使用CreateFileMapping函数，利用他我们可以设定一些读写属性:PAGE_READONLY,PAGE_READWRITE,PAGE_WRITECOPY.第一参数指定只能对该映射文件进行读操作。任何写操作将导致内存访问错误。第二个参数则指明可以对映射文件进行读写。这时候，任何对文件的读写都是直接操作文件的。而对于第三个参数PAGE_WRITECOPY顾名思义就是写入时拷贝，任何向这段内存写入的操作(因为文件是映射到进程地址空间的，对这段空间的读写就相当于对文件进行的直接读写)都将被系统捕获，并重新在你的虚拟地址空间重新保留并分配一段内存，你所写入的一切东西都将在这里，而且你原先的指向映射文件的内存地址也会实际指向这段重新分配的内存，于是在进程结束后，映射文件内容并没有改变，只是在运行期间在那段私有拷贝的内存里面存在着你修改的内容。windows进程运行所需要映射的一些系统dll就是以这种方式映射的，比如常用的ntdll.dll,kernel32.dll,gdi32.dll.几乎所有的进程都会加载这三个动态库。如果你在一个进程里修改这个映射文件的内容，并不会影响到其他的进程使用他们。你所修改的只是在本进程的地址空间之内的。事实上原始文件并没有被改变。<br />这样，在后面的修改系统api的时候，实际就是修改这些动态库地址内的内容。前面说到这不是修改全局api就是这个原因，因为他们都是以写入时拷贝的方式来映射的。不过这已经足够了，windows提供了2个强大的内存操作函数ReadProcessMemory和WriteProcessMemory.利用这两个函数我们就可以随便对任意进程的任意用户地址空间进行读写了。但是，现在有一个问题，我们该写什么，说了半天，怎么实现跳转呢？现在来看一个简单的例子：<br />MessageBox(NULL, "World", "Hello", 0);<br />我们在执行这条语句的时候，调用了系统api MessageBox，实际上在程序中我没有定义UNICODE宏，系统调用的是MessageBox的ANSI版本MessageBoxA,这个函数是由user32.dll导出的。下面是执行这条语句的汇编代码：<br />0040102A   push     0<br />0040102C   push     offset string "Hello" (0041f024)<br />00401031   push     offset string "World" (0041f01c)<br />00401036   push     0<br />00401038   call     dword ptr [__imp__MessageBoxA@16 (0042428c)]<br />前面四条指令分别为参数压栈，因为MessageBoxA是__stdcall调用约定，所以参数是从右往左压栈的。最后再CALL 0x0042428c<br /><br />看看0042428c这段内存的值：<br />0042428C 0B 05 D5 77 00 00 00<br />可以看到这个值0x77d5050b,正是user32.dll导出函数MessageBoxA的入口地址。<br /><br />这是0x77D5050B处的内容， <br />77D5050B 8B FF           mov       edi,edi<br />77D5050D 55             push     ebp<br />77D5050E 8B EC           mov       ebp,esp<br />理论上只要改变api入口和出口的任何机器码，都可以拦截该api。这里我选择最简单的修改方法，直接修改api入口的前十个字节来实现跳转。为什么是十字节呢？其实修改多少字节都没有关系，只要实现了函数的跳转之后，你能把他们恢复并让他继续运行才是最重要的。在CPU的指令里，有几条指令可以改变程序的流程：JMP，CALL，INT，RET，RETF，IRET等指令。这里我选择CALL指令，因为他是以函数调用的方式来实现跳转的，这样可以带一些你需要的参数。到这里，我该说说函数的堆栈了。<br /><br />总结：windows进程所需要的动态库文件都是以写入时拷贝的方式映射到进程地址空间中的。这样，我们只能拦截指定的进程。修改目标进程地址空间中的指定api的入口和出口地址之间的任意数据，使之跳转到我们的拦截代码中去，然后再恢复这些字节，使之能顺利工作。<br /><br /><br /><br /><br />二：函数堆栈的一些知识<br /><br />  正如前面所看到MessageBoxA函数执行之前的汇编代码，首先将四个参数压栈，然后CALL MessageBoxA，这时候我们的线程堆栈看起来应该是这样的：<br /><br />|   |   &lt;---ESP<br />|返回地址|<br />|参数1|<br />|参数2|<br />|参数3|<br />|参数4|<br />|..   |<br /><br />我们再看MessageBoxA的汇编代码，<br />77D5050B 8B FF           mov       edi,edi<br />77D5050D 55             push     ebp<br />77D5050E 8B EC           mov       ebp,esp<br />注意到堆栈的操作有PUSH ebp,这是保存当前的基址指针，以便一会儿恢复堆栈后返回调用线程时使用，然后再有mov ebp,esp就是把当前esp的值赋给ebp，这时候我们就可以使用 ebp+偏移 来表示堆栈中的数据，比如参数1就可以表示成[ebp+8]，返回地址就可以表示成[ebp+4]..如果我们在拦截的时候要对这些参数和返回地址做任何处理，就可以使用这种方法。如果这个时候函数有局部变量的话，就通过减小ESP的值的方式来为之分配空间。接下来就是保存一些寄存器：EDI,ESI,EBX.要注意的是，函数堆栈是反方向生长的。这时候堆栈的样子：<br />|....|<br />|EDI| &lt;---ESP<br />|ESI|<br />|EBX|<br />|局部变量| <br />|EBP   |   <br />|返回地址|<br />|参数1|<br />|参数2|<br />|参数3|<br />|参数4|<br />|..   |<br /><br />在函数返回的时候，由函数自身来进行堆栈的清理，这时候清理的顺序和开始入栈的顺序恰恰相反，类似的汇编代码可能是这样的：<br /><br />pop edi<br />pop esi<br />pop ebx<br />add esp, 4<br />pop ebp<br />ret 0010<br />先恢复那些寄存器的值，然后通过增加ESP的值的方式来释放局部变量。这里可以用mov esp, ebp来实现清空所有局部变量和其他一些空闲分配空间。接着函数会恢复EBP的值，利用指令POP EBP来恢复该寄存器的值。接着函数运行ret 0010这个指令。该指令的意思是，函数把控制权交给当前栈顶的地址的指令，同时清理堆栈的16字节的参数。如果函数有返回值的话，那在EAX寄存器中保存着当前函数的返回值。如果是__cdecl调用方式，则执行ret指令，对于堆栈参数的处理交给调用线程去做。如wsprintf函数。<br /><br />这个时候堆栈又恢复了原来的样子。线程得以继续往下执行...<br />在拦截api的过程之中一个重要的任务就是保证堆栈的正确性。你要理清每一步堆栈中发生了什么。<br /><br /><br /><br />三：形成思路<br />  <br />  呵呵，不知道你现在脑海是不是有什么想法。怎么去实现拦截一个api？<br />  这里给出一个思路，事实上拦截的方法真的很多，理清了一个，其他的也就容易了。而且上面所说的2个关键知识，也可以以另外的形式来利用。<br />  我以拦截CreateFile这个api为例子来简单说下这个思路吧：<br />  <br />  首先，既然我们要拦截这个api就应该知道这个函数在内存中的位置吧，至少需要知道从哪儿入口。CreateFile这个函数是由kernel32.dll这个动态库导出的。我们可以使用下面的方法来获取他映射到内存中的地址：<br />  HMODULE hkernel32 = LoadLibrary("Kernel32.dll");<br />  PVOID dwCreateFile = GetProcAddress(hkernei32, "CreateFileA");<br />这就可以得到createfile的地址了，注意这里是获取的createfile的ansic版本。对于UNICODE版本的则获取CreateFileW。这时dwCreateFile的值就是他的地址了。对于其他进程中的createfile函数也是这个地址，前面说过windows指定了他提供的所有的dll文件的加载地址。<br />  <br />  接下来，我们该想办法实现跳转了。最简单的方法就是修改这个api入口处的代码了。但是我们该修改多少呢？修改的内容为什么呢？前面说过我们可以使用CALL的方式来实现跳转，这种方法的好处是可以为你的拦截函数提供一个或者多个参数。这里只要一个参数就足够了。带参数的函数调用的汇编代码是什么样子呢，前面也已经说了，类似与调用MessageBoxA时的代码：<br /><br />PUSH 参数地址<br />CALL 函数入口地址(这里为一个偏移地址)<br /><br />执行这2条指令就能跳转到你要拦截的函数了，但是我们该修改成什么呢。首先，我们需要知道这2条指令的长度和具体的机器代码的值。其中PUSH对应0x68，而CALL指令对应的机器码为0xE8,而后面的则分别对应拦截函数的参数地址和函数的地址。注意第一个是一个直接的地址，而第二个则是一个相对地址。当然你也可以使用0xFF0x15这个CALL指令来进行直接地址的跳转。<br />下面就是计算这2个地址的值了，<br />对于参数和函数体的地址，要分情况而定，对于对本进程中api的拦截，则直接取地址就可以了。对于参数，可以先定义一个参数变量，然后取变量地址就ok了。<br />如果是想拦截其他进程中的api，则必须使用其他一些方法，最典型的方法是利用VirtualAllocEx函数来在其他进程中申请和提交内存空间。然后用WriteProcessMemory来分别把函数体和参数分别写入申请和分配的内存空间中去。然后再生成要修改的数据，最后用WriteProcessMemory来修改api入口，把入口的前10字节修改为刚刚生成的跳转数据。比如在远程进程中你写入的参数和函数体的内存地址分别为0x00010000和0x00011000,则生成的跳转数据为 68 00 00 01 00 E8 00 10 01 00(PUSH 00010000 CALL 00011000),这样程序运行createfile函数的时候将会先运行PUSH 00010000 CALL 00011000，这样就达到了跳转的目的。此刻我们应该时刻注意堆栈的状态，对于CreateFile有<br />HANDLE CreateFile(<br />LPCTSTR lpFileName,<br />DWORD dwDesiredAccess,<br />DWORD dwShareMode,<br />LPSECURITY_ATTRIBUTES lpSecurityAttributes,<br />DWORD dwCreationDisposition,<br />DWORD dwFlagsAndAttributes,<br />HANDLE hTemplateFile<br />);<br />可以看到其有7个参数，于是在调用之前，堆栈应该已经被压入了这7个参数，堆栈的样子：<br />|....|   &lt;---ESP<br />|createfile执行后的下一条指令地址|<br />|参数1|<br />|参数2|<br />|参数3|<br />|参数4|<br />|参数5|<br />|参数6|<br />|参数7|<br />|..|<br /><br />这是执行到我们的跳转语句：PUSH 00010000,于是堆栈又变了：<br /><br />|....|   &lt;---ESP<br />|00010000|<br />|createfile执行后的下一条指令地址|<br />|参数1|<br />|参数2|<br />|参数3|<br />|参数4|<br />|参数5|<br />|参数6|<br />|参数7|<br />|..|<br /><br />接着执行CALL 00011000,堆栈变为：<br />|...| &lt;---ESP<br />|api入口之后的第11个字节的指令的地址|   <br />|00010000|<br />|createfile执行后的下一条指令地址|<br />|参数1|<br />|参数2|<br />|参数3|<br />|参数4|<br />|参数5|<br />|参数6|<br />|参数7|<br />|..|<br /><br />接下来就到了我们的拦截函数中拉，当然，函数肯定也会做一些类似动作，把EBP压栈，为局部变量分配空间等。这时候堆栈的样子又变了：<br /><br />|EDI| &lt;---ESP<br />|ESI|<br />|EBX|<br />|局部变量| <br />|EBP|   &lt;---EBP<br />|api入口之后的第11个字节的指令的地址|   <br />|00010000|<br />|createfile执行后的下一条指令地址|<br />|参数1|<br />|参数2|<br />|参数3|<br />|参数4|<br />|参数5|<br />|参数6|<br />|参数7|<br />|..|<br /><br />这时候，你想做什么就尽情地做吧，获取参数信息，延缓执行CreateFile函数等等。拿获取打开文件句柄的名字来说吧，文件名是第一个参数，前面说过我们可以用[EBP+8]来获取参数，但是对照上面的堆栈形状，中间又加了另外一些数据，所以我们用[EBP+16]来获取第一个参数的地址。比如：<br />char* PFileName = NULL;<br />__asm{<br />MOV EAX,[EBP+16]<br />MOV [szFileName], EAX<br />}<br /><br />比如我们用一个messagebox来弹出一个信息，说明该程序即将打开一个某谋路径的文件句柄。但是有一个要注意的是，如果你想拦截远程进程的话，对于那个拦截函数中所使用到的任何函数或者以任何形式的相对地址的调用都要停止。因为每个进程中的地址分配都是独立的，比如上面的CALL MessageBoxA改成直接地址的调用。对于使用messagebox，我们应该定义一个函数指针，然后把这个指针的值赋值为user32.dll中导出该函数的直接地址。然后利用这个指针来进行函数调用。对于messagebox函数的调用可以这样，在源程序中定义一个参数结构体，参数中包含一个导出函数的地址,把这个地址设为MessageBoxA的直接地址，获取地址的方法就不说了。然后把这个参数传给拦截函数，就可以使用拉。这也是利用一个参数的原因。类似代码如下：<br /><br /><br />typedef struct _RemoteParam {<br />  DWORD dwMessageBox;<br />} RemoteParam, * PRemoteParam;<br /><br />typedef int (__stdcall * PFN_MESSAGEBOX)(HWND, LPCTSTR, LPCTSTR, DWORD);//定义一个函数指针<br /><br />//拦截函数<br />void HookCreateFile(LPVOID lParam)<br />{<br />RemoteParam* pRP = (RemoteParam*)lParam;//获取参数地址<br />char* PFileName = NULL;//定义一个指针<br />__asm{<br />MOV EAX,[EBP+16]<br />MOV [szFileName], EAX //把CreateFile第一个参数的值，文件的路径的地址传               //给szFileName<br />}<br /><br />//定 义一个函数指针<br />PFN_MESSAGEBOX pfnMessageBox = (PFN_MESSAGEBOX)pRP-&gt;dwMessageBox;<br /><br />pfnMessageBox(NULL, PFileName, PFileName, MB_ICONINFORMATION |MB_OK);<br />//输出要打开的文件的路径<br />//.....<br />}<br /><br />对于你要使用的其他函数，都是使用同样的方式，利用这个参数来传递我们要传递的函数的绝对地址，然后定义这个函数指针，就可以使用了。<br /><br /><br />好了，接下来我们该让被拦截的api正常工作了，这个不难，把他原来的数据恢复一下就可以了。那入口的10个字节。我们在改写他们的时候应该保存一下，然后也把他放在参数中传递给拦截函数，呵呵，参数的作用可多了。接着我们就可以用WriteProcessMemory函数来恢复这个api的入口了，代码如下：<br />PFN_GETCURRENTPROCESS pfnGetCurrentProcess = (PFN_GETCURRENTPROCESS)pRP-&gt;dwGetCurrentProcess;<br />PFN_WRITEPROCESSMEMORY pfnWriteProcessMemory = (PFN_WRITEPROCESSMEMORY)pRP-&gt;dwWriteProcessMemory;<br />  <br />if(!pfnWriteProcessMemory(pfnGetCurrentProcess(),<br />                            (LPVOID)pfnConnect,<br />                            (LPCVOID)pRP-&gt;szOldCode,<br />                            10,<br />                            NULL))<br />pfnMessageBox(NULL, pRP-&gt;szModuleName1, pRP-&gt;szModuleName2, MB_ICONINFORMATION | MB_OK);<br />其中这些函数指针的定义和上面的类似。<br />而参数中的szoldcode则是在源程序中在修改api之前保存好，然后传给拦截函数，在源程序中是用ReadProcessMemory函数来获取他的前10个字节的：<br />ReadProcessMemory(GetCurrentProcess(),<br />                      (LPCVOID)RParam.dwCreateFile,<br />                      oldcode,<br />                      10,<br />                      &amp;dwPid)<br />strcat((char*)RParam.szOldCode, (char*)oldcode);<br /><br /><br />接下来如果你还继续保持对该api的拦截，则又该用WriteProcessMemory 来修改入口了，跟前面的恢复入口是一样的，只不过把szOldCode换成了szNewCode了而已。这样你又能对CreateFile继续拦截了。<br /><br />好了，接下来该进行堆栈的清理了，也许你还要做点其他事情，尽管做去。但是清理堆栈是必须要做的，在函数结束的时候，因为在我们放任api恢复执行之后，他又return 到我们的函数中来了，这个时候的堆栈是什么样子呢？<br />|EDI| &lt;---ESP<br />|ESI|<br />|EBX|<br />|局部变量| <br />|EBP|   &lt;---EBP<br />|api入口之后的第11个字节的指令的地址|   <br />|00010000|<br />|createfile执行后的下一条指令地址|<br />|参数1|<br />|参数2|<br />|参数3|<br />|参数4|<br />|参数5|<br />|参数6|<br />|参数7|<br />|..|<br /><br />我们的目标是把返回值记录下来放到EAX寄存器中去，把返回地址记录下来，同时把堆栈恢复成原来的样子。<br />首先我们恢复那些寄存器的值，接着释放局部变量，可以用mov esp, ebp.因为我们不清楚具体的局部变量分配了多少空间。所以使用这个方法。<br /><br /><br />__asm<br />{POP EDI<br />POP ESI<br />POP EBX   //恢复那些寄存器<br />MOV EDX, [NextIpAddr]//把返回地址放到EDX中，因为待会儿             //EBX被恢复后，线程中的所有局部变量就不能正常使用了。<br />      <br />MOV EAX, [RetValue]//返回值放到EAX中，当然也可以修改这个返回值<br />MOV ESP, EBP//清理局部变量<br />POP EBP//恢复EBP的值<br />ADD ESP, 28H //清理参数和返回地址，注意一共(7+1+1+1)*4<br />PUSH EDX //把返回地址压栈，这样栈中就只有这一个返回地址了，返回之后栈       //就空了<br />RET<br />}<br /><br />这样，一切就完成了，堆栈恢复了应该有的状态，而你想拦截的也拦截到了。<br /><br /><br />四：后记<br />  拦截的方式多种多样，不过大体的思路却都相同。要时刻注意你要拦截的函数的堆栈状态以及在拦截函数中的对数据的引用和函数的调用（地址问题）。<br /><br />  <br />//////////////////////////////////////////////////////////////////////<br />附录：一个拦截CreateFile函数的简单实现<br />//////////////////////////////////////////////////////////////////////<br /></font>
				<div style="FONT-SIZE: 9px; MARGIN-LEFT: 5px">
						<b>CODE:</b>
				</div>
				<div class="quote" id="code1">
						<br />#include &lt;stdio.h&gt;<br />#include &lt;windows.h&gt;<br />#include &lt;Psapi.h&gt;<br /><br />#pragma comment(lib, "psapi.lib")<br /><br />typedef struct _RemoteParam {<br />  DWORD dwCreateFile;<br />  DWORD dwMessageBox;<br />  DWORD dwGetCurrentProcess;<br />  DWORD dwWriteProcessMemory;<br />  unsigned char szOldCode[10];<br />  DWORD FunAddr;<br />} RemoteParam, * PRemoteParam;<br /><br />typedef HANDLE (__stdcall * PFN_CREATEFILE)(LPCTSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE);<br />typedef int (__stdcall * PFN_MESSAGEBOX)(HWND, LPCTSTR, LPCTSTR, DWORD);<br />typedef BOOL (__stdcall * PFN_WRITEPROCESSMEMORY)(HANDLE,LPVOID,LPCVOID,SIZE_T,SIZE_T*);<br />typedef HANDLE (__stdcall * PFN_GETCURRENTPROCESS)(void);<br /><br />#define PROCESSNUM 128<br />#define MYMESSAGEBOX "MessageBoxW"<br />#define MYCREATEFILE "CreateFileW"<br /><br />void HookCreateFile(LPVOID lParam)<br />{<br /><br />  RemoteParam* pRP = (RemoteParam*)lParam;<br /><br /><br />  DWORD NextIpAddr = 0;<br />  DWORD dwParamaAddr = 0;<br /><br />  HANDLE RetFpHdl = INVALID_HANDLE_VALUE;<br />  LPCTSTR lpFileName;<br />  DWORD dwDesiredAccess;<br />  DWORD dwShareMode;<br />  LPSECURITY_ATTRIBUTES lpSecurityAttributes;<br />  DWORD dwCreationDisposition;<br />  DWORD dwFlagsAndAttributes;<br />  HANDLE hTemplateFile;<br />  PFN_CREATEFILE pfnCreatefile = (PFN_CREATEFILE)pRP-&gt;dwCreateFile; <br /><br /><br />  __asm <br />  {<br />  MOV EAX,[EBP+8]<br />  MOV [dwParamaAddr], EAX<br />  MOV EAX,[EBP+12]       <br />  MOV [NextIpAddr], EAX<br />  MOV EAX,[EBP+16]<br />  MOV [lpFileName], EAX<br />  MOV EAX,[EBP+20]<br />  MOV [dwDesiredAccess],EAX<br />  MOV EAX,[EBP+24]<br />  MOV [dwShareMode],EAX<br />  MOV EAX,[EBP+28]<br />  MOV [lpSecurityAttributes],EAX<br />  MOV EAX,[EBP+32]<br />  MOV [dwCreationDisposition],EAX<br />  MOV EAX,[EBP+36]<br />  MOV [dwFlagsAndAttributes],EAX<br />  MOV EAX,[EBP+40]<br />  MOV [hTemplateFile],EAX   <br />  }<br /><br />  PFN_MESSAGEBOX pfnMessageBox = (PFN_MESSAGEBOX)pRP-&gt;dwMessageBox;<br />  int allowFlag = pfnMessageBox(NULL, lpFileName, NULL, MB_ICONINFORMATION | MB_YESNO);<br />  <br />  if(allowFlag == IDYES)<br />  {<br />  unsigned char szNewCode[10];<br />  int PramaAddr = (int)dwParamaAddr;<br />  szNewCode[4] = PramaAddr&gt;&gt;24;<br />  szNewCode[3] = (PramaAddr&lt;&lt;8)&gt;&gt;24;<br />  szNewCode[2] = (PramaAddr&lt;&lt;16)&gt;&gt;24;<br />  szNewCode[1] = (PramaAddr&lt;&lt;24)&gt;&gt;24;<br />  szNewCode[0] = 0x68;<br />  <br />  int funaddr = (int)pRP-&gt;FunAddr - (int)pfnCreatefile - 10 ;<br />  szNewCode[9] = funaddr&gt;&gt;24;<br />  szNewCode[8] = (funaddr&lt;&lt;8)&gt;&gt;24;<br />  szNewCode[7] = (funaddr&lt;&lt;16)&gt;&gt;24;<br />  szNewCode[6] = (funaddr&lt;&lt;24)&gt;&gt;24;<br />  szNewCode[5] = 0xE8;<br />  <br />  <br />  PFN_GETCURRENTPROCESS pfnGetCurrentProcess = (PFN_GETCURRENTPROCESS)pRP-&gt;dwGetCurrentProcess;<br />  PFN_WRITEPROCESSMEMORY pfnWriteProcessMemory = (PFN_WRITEPROCESSMEMORY)pRP-&gt;dwWriteProcessMemory;<br />  pfnWriteProcessMemory(pfnGetCurrentProcess(),<br />                (LPVOID)pfnCreatefile,<br />                (LPCVOID)pRP-&gt;szOldCode,<br />                10,<br />                NULL);<br /><br />  RetFpHdl = pfnCreatefile(lpFileName,<br />                  dwDesiredAccess,<br />                  dwShareMode,<br />                  lpSecurityAttributes,<br />                  dwCreationDisposition,<br />                  dwFlagsAndAttributes,<br />                  hTemplateFile);<br />  pfnWriteProcessMemory(pfnGetCurrentProcess(),<br />                (LPVOID)pfnCreatefile,<br />                (LPCVOID)szNewCode,<br />                10,<br />                NULL);<br />  }<br /><br /><br />  __asm<br />    {POP EDI<br />      POP ESI<br />      POP EBX<br />      MOV EDX, [NextIpAddr]<br />      MOV EAX, [RetFpHdl]<br />      MOV ESP, EBP<br />      POP EBP<br />      ADD ESP, 28H <br />      PUSH EDX<br />      RET<br />    }<br /><br />  <br />}<br /><br /><br /><br />BOOL AdjustProcessPrivileges(LPCSTR szPrivilegesName)<br />{<br />  HANDLE hToken; <br />  TOKEN_PRIVILEGES tkp;<br /><br />  if(!OpenProcessToken(GetCurrentProcess(),<br />    TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&amp;hToken))<br />  {<br />    return FALSE;<br />  }<br /><br />  if(!LookupPrivilegeValue(NULL,szPrivilegesName,<br />                  &amp;tkp.Privileges[0].Luid))<br />  {<br />    CloseHandle(hToken);<br />    return FALSE;<br />  }<br />  <br />  tkp.PrivilegeCount = 1;<br />  tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;<br />  <br />  if(!AdjustTokenPrivileges(hToken,FALSE,&amp;tkp,sizeof(tkp),NULL,NULL))<br />  {<br />    CloseHandle(hToken);<br />    return FALSE;<br />  }<br />  <br />  CloseHandle(hToken);<br />  return TRUE;<br />}<br /><br /><br />void printProcessNameByPid( DWORD ProcessId )<br />{<br />  HANDLE pHd;<br />  HMODULE pHmod;<br />  char ProcessName[MAX_PATH] = "unknown";<br />  DWORD cbNeeded;<br />  pHd = OpenProcess( PROCESS_QUERY_INFORMATION |PROCESS_VM_READ, FALSE, ProcessId );<br />  if(pHd == NULL)<br />    return;<br />  <br />  if(!EnumProcessModules( pHd, &amp;pHmod, sizeof(pHmod), &amp;cbNeeded))<br />    return;<br />  if(!GetModuleFileNameEx( pHd, pHmod, ProcessName, MAX_PATH))<br />    return;<br />  <br />  printf( "%d\t%s\n", ProcessId, ProcessName);<br />  CloseHandle( pHd );<br />  return;<br />}<br /><br /><br />int main(void)<br />{<br /><br />  if(!AdjustProcessPrivileges(SE_DEBUG_NAME))<br />  {<br />      printf("AdjustProcessPrivileges Error!\n");<br />      return -1;<br />  }<br /><br />  DWORD Pids[PROCESSNUM];<br />  DWORD dwProcessNum = 0;<br />  if(!EnumProcesses(Pids, sizeof(Pids), &amp;dwProcessNum))<br />  {<br />      printf("EnumProcess Error!\n");<br />      return -1;<br />  }<br />  <br />  for( DWORD num = 0; num &lt; (dwProcessNum / sizeof(DWORD)); num++)<br />      printProcessNameByPid(Pids[num]);<br /><br />  printf("\nAll %d processes running. \n", dwProcessNum / sizeof(DWORD));<br /><br />  DWORD dwPid = 0;<br />  printf("\n请输入要拦截的进程id:");<br />  scanf("%d", &amp;dwPid);<br />  <br />  HANDLE hTargetProcess = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, dwPid);<br />  if(hTargetProcess == NULL)<br />  {<br />      printf("OpenProcess Error!\n");<br />      return -1;<br />  }<br /><br />  DWORD dwFunAddr = (DWORD)VirtualAllocEx(hTargetProcess, NULL, 8192, <br />                              MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);<br />  <br />  if((LPVOID)dwFunAddr == NULL)<br />  {<br />      printf("申请线程内存失败!\n");<br />      CloseHandle(hTargetProcess);<br />      return -1;<br />  }<br /><br />  DWORD dwPramaAddr = (DWORD)VirtualAllocEx(hTargetProcess, NULL, sizeof(RemoteParam), <br />                              MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);<br /><br />  if((LPVOID)dwPramaAddr == NULL)<br />  {<br />      printf("申请参数内存失败!\n");<br />      CloseHandle(hTargetProcess);<br />      return -1;<br />  }<br /><br />  printf("\n线程内存地址:%.8x\n"<br />        "参数内存地址:%.8x\n",<br />        dwFunAddr, dwPramaAddr);<br />    RemoteParam RParam;<br />  ZeroMemory(&amp;RParam, sizeof(RParam));<br />  HMODULE hKernel32 = LoadLibrary("kernel32.dll");<br />  HMODULE hUser32 = LoadLibrary("user32.dll");<br /><br />  RParam.dwCreateFile = (DWORD)GetProcAddress(hKernel32, MYCREATEFILE);<br />  RParam.dwGetCurrentProcess = (DWORD)GetProcAddress(hKernel32, "GetCurrentProcess");<br />  RParam.dwWriteProcessMemory = (DWORD)GetProcAddress(hKernel32, "WriteProcessMemory");<br />  RParam.dwMessageBox = (DWORD)GetProcAddress(hUser32, MYMESSAGEBOX); <br />  <br />  unsigned char oldcode[10];<br />  unsigned char newcode[10];<br />  int praadd = (int)dwPramaAddr;<br />  int threadadd = (int)dwFunAddr;<br />  newcode[4] = praadd&gt;&gt;24;<br />  newcode[3] = (praadd&lt;&lt;8)&gt;&gt;24;<br />  newcode[2] = (praadd&lt;&lt;16)&gt;&gt;24;<br />  newcode[1] = (praadd&lt;&lt;24)&gt;&gt;24;<br />  newcode[0] = 0x68;<br />  <br />  int offsetaddr = threadadd - (int)RParam.dwCreateFile - 10 ;<br />  newcode[9] = offsetaddr&gt;&gt;24;<br />  newcode[8] = (offsetaddr&lt;&lt;8)&gt;&gt;24;<br />  newcode[7] = (offsetaddr&lt;&lt;16)&gt;&gt;24;<br />  newcode[6] = (offsetaddr&lt;&lt;24)&gt;&gt;24;<br />  newcode[5] = 0xE8;<br /><br />  printf("NewCode:");<br />  for(int j = 0; j &lt; 10; j++)<br />      printf("0x%.2x ",newcode[j]);<br />  printf("\n\n");<br /><br /><br /><br />  if(!ReadProcessMemory(GetCurrentProcess(),<br />                  (LPCVOID)RParam.dwCreateFile,<br />                  oldcode,<br />                  10,<br />                  &amp;dwPid))<br />  {<br />      printf("read error");<br />      CloseHandle(hTargetProcess);<br />      FreeLibrary(hKernel32);<br />      return -1;<br />  }<br /><br />  strcat((char*)RParam.szOldCode, (char*)oldcode);<br />  RParam.FunAddr = dwFunAddr;<br /><br />  printf(<br />        "RParam.dwCreateFile:%.8x\n"<br />        "RParam.dwMessageBox:%.8x\n"<br />        "RParam.dwGetCurrentProcess:%.8x\n"<br />        "RParam.dwWriteProcessMemory:%.8x\n"<br />        "RParam.FunAddr:%.8x\n",<br />        RParam.dwCreateFile,<br />        RParam.dwMessageBox,<br />        RParam.dwGetCurrentProcess,<br />        RParam.dwWriteProcessMemory,<br />        RParam.FunAddr);<br />  printf("RParam.szOldCode:");<br />  for( int i = 0; i&lt; 10; i++)<br />      printf("0x%.2x ", RParam.szOldCode[i]);<br />  printf("\n");<br />  <br />  <br />  if(!WriteProcessMemory(hTargetProcess, (LPVOID)dwFunAddr, (LPVOID)&amp;HookCreateFile, 8192, &amp;dwPid))<br />  {<br />      printf("WriteRemoteProcessesMemory Error!\n");<br />      CloseHandle(hTargetProcess);<br />      FreeLibrary(hKernel32);<br />      return -1; <br />  }<br /><br />  if(!WriteProcessMemory(hTargetProcess, (LPVOID)dwPramaAddr, (LPVOID)&amp;RParam, sizeof(RemoteParam), &amp;dwPid))<br />  {<br />      printf("WriteRemoteProcessesMemory Error!\n");<br />      CloseHandle(hTargetProcess);<br />      FreeLibrary(hKernel32);<br />      return -1; <br />  }<br />  <br />  if(!WriteProcessMemory(hTargetProcess, (LPVOID)RParam.dwCreateFile, (LPVOID)newcode, 10, &amp;dwPid))<br />  {<br />      printf("WriteRemoteProcessesMemory Error!\n");<br />      CloseHandle(hTargetProcess);<br />      FreeLibrary(hKernel32);<br />      return -1; <br />  }<br /><br />  printf("\nThat's all, good luck :)\n");<br />  CloseHandle(hTargetProcess);<br />  FreeLibrary(hKernel32);<br />  return 0;<br />}</div>
		</span>
<img src ="http://www.cppblog.com/saga/aggbug/17891.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/saga/" target="_blank">saga.constantine</a> 2007-01-22 16:49 <a href="http://www.cppblog.com/saga/archive/2007/01/22/17891.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[收集]关于汇编80X87FPU浮点运算</title><link>http://www.cppblog.com/saga/archive/2007/01/17/17721.html</link><dc:creator>saga.constantine</dc:creator><author>saga.constantine</author><pubDate>Wed, 17 Jan 2007 06:46:00 GMT</pubDate><guid>http://www.cppblog.com/saga/archive/2007/01/17/17721.html</guid><wfw:comment>http://www.cppblog.com/saga/comments/17721.html</wfw:comment><comments>http://www.cppblog.com/saga/archive/2007/01/17/17721.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/saga/comments/commentRss/17721.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/saga/services/trackbacks/17721.html</trackback:ping><description><![CDATA[
		<p>
				<font color="#006400">80X87FPU浮点数据的格式、浮点寄存器的特点<br /></font>
				<br />
				<font color="#ff0000">浮点数据格式:<br /></font>在计算机中，实数的浮点格式（Floating-Point Format）所示，分成指数、有效数字和符号位三个部分。<br />·  符号（Sign）——表示数据的正负，在最高有效位（MSB）。负数的符号位为1，正数的符号为0。<br />·  指数（Exponent）——也被称为阶码，表示数据以2为底的幂。指数采用偏移码（Biased Exponent）表示，恒为整数。<br />·  有效数字（Significand）——表示数据的有效数字，反映数据的精度。有效数字一般采用规格化（Normalized）形式，是一个纯小数，所以也被称为尾数（Mantissa）、小数或分数（Fraction）。<br />      80x87支持三种浮点数据类型：单精度、双精度和扩展精度；它们的长度依次为32、64和80位，即4、8和10个字节；<br />·  单精度浮点数（32位短实数）——由1位符号、8位指数、23位有效数组成。<br />·  双精度浮点数（64位长实数）——由1位符号、11位指数、52位有效数组成。<br />·  扩展精度浮点数（80位临时实数）——由1位符号、15位指数、64位有效数组成。很多计算机中并没有80位扩展精度这种数据类型，80x87 FPU主要在内部使用它存贮中间结果，以保证最终数值的精度。</p>
		<p>
				<font color="#ff0000">80x87的指令系统<br /></font>浮点处理单元FPU具有自己的指令系统，共有几十种浮点指令，可以分成传送、算术运算、超越函数、比较、FPU控制等类。浮点指令归属于ESC指令，其前5位的操作码都是11011b，它的指令助记符均以F开头。<br />1. 浮点传送类指令<br />    浮点数据传送指令完成主存与栈顶st(0)、数据寄存器st(i)与栈顶之间的浮点格式数据的传送。浮点数据寄存器是一个首尾相接的堆栈，所以它的数据传送实际上是对堆栈的操作，有些要改变堆栈指针TOP，即修改当前栈顶。<br />2. 算术运算类指令<br />    这类浮点指令实现浮点数、16/32位整数的加、减、乘、除运算，它们支持的寻址方式相同。这组指令还包括有关算术运算的指令，例如求绝对值、取整等。<br />3. 超越函数类指令<br />    浮点指令集中包含有进行三角函数、指数和对数运算的指令。<br />4. 浮点比较类指令<br />    浮点比较指令比较栈顶数据与指定的源操作数，比较结果通过浮点状态寄存器反映。<br />5. FPU控制类指令<br />    FPU控制类指令用于控制和检测浮点处理单元FPU的状态及操作方式。</p>
		<p>
				<font color="#ff0000">采用浮点指令的汇编语言程序格式，与整数指令源程序格式是类似的，但有以下几点需要注意：</font>
				<br />·  使用FPU选择伪指令<br />      由于汇编程序MASM默认只识别8086指令，所以要加上.8087 / .287 / .387等伪指令选择汇编浮点指令；有时，还要加上相应的.238/.386等伪指令。<br />·  定义浮点数据<br />      数据定义伪指令dd(dword) / dq(qword) / dt(tbyte)依次说明32/64/80位数据；它们可以用于定义单精度、双精度和扩展精度浮点数。为了区别于整数定义，MASM 6.11建议采用REAL4、REAL8、REAL10定义单、双、扩展精度浮点数，但不能出现纯整数（其实，整数后面补个小数点就可以了）。相应的数据属性依次是dword、qword、tbyte。另外，实常数可以用E表示10的幂。<br />·  初始化浮点处理单元 <br />      每当执行一个新的浮点程序时，第一条指令都应该是初始化FPU的指令finit。该指令清除浮点数据寄存器栈和异常，为程序提供一个“干净”的初始状态。否则，遗留在浮点寄存器栈中的数据可能会产生堆栈溢出。另一方面，浮点指令程序段结束，也最好清空浮点数据寄存器。</p>
		<p>
				<font color="#ff0000">浮点寄存器:<br /></font>浮点执行环境的寄存器主要是8个通用数据寄存器和几个专用寄存器，它们是状态寄存器、控制寄存器、标记寄存器等<br />8个浮点数据寄存器（FPU Data Register），编号FPR0 ~ FPR7。每个浮点寄存器都是80位的，以扩展精度格式存储数据。当其他类型数据压入数据寄存器时，PFU自动转换成扩展精度；相反，数据寄存器的数据取出时，系统也会自动转换成要求的数据类型。<br />      8个浮点数据寄存器组成首尾相接的堆栈，当前栈顶ST(0)指向的FPRx由状态寄存器中TOP字段指明。数据寄存器不采用随机存取，而是按照“后进先出”的堆栈原则工作，并且首尾循环。向数据寄存器传送（Load）数据时就是入栈，堆栈指针TOP先减1，再将数据压入栈顶寄存器；从数据寄存器取出（Store）数据时就是出栈，先将栈顶寄存器数据弹出，再修改堆栈指针使TOP加1。浮点寄存器栈还有首尾循环相连的特点。例如，若当前栈顶TOP=0（即ST(0) = PFR0），那么，入栈操作后就使TOP=7（即使ST(0) = PFR7），数据被压入PFR7。所以，浮点数据寄存器常常被称为浮点数据栈。<br />      为了表明浮点数据寄存器中数据的性质，对应每个FPR寄存器，都有一个2位的标记（Tag）位，这8个标记tag0 ~ tag7组成一个16位的标记寄存器。</p>
<img src ="http://www.cppblog.com/saga/aggbug/17721.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/saga/" target="_blank">saga.constantine</a> 2007-01-17 14:46 <a href="http://www.cppblog.com/saga/archive/2007/01/17/17721.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转贴]内存对齐与ANSI C中struct型数据的内存布局（Struct Alignment）</title><link>http://www.cppblog.com/saga/archive/2006/05/28/7774.html</link><dc:creator>saga.constantine</dc:creator><author>saga.constantine</author><pubDate>Sun, 28 May 2006 08:15:00 GMT</pubDate><guid>http://www.cppblog.com/saga/archive/2006/05/28/7774.html</guid><wfw:comment>http://www.cppblog.com/saga/comments/7774.html</wfw:comment><comments>http://www.cppblog.com/saga/archive/2006/05/28/7774.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/saga/comments/commentRss/7774.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/saga/services/trackbacks/7774.html</trackback:ping><description><![CDATA[选择自 soloist 的 Blog 作者:不详  如原作者发现并不允许转载请通知我，我会删除！<img src="../../Emoticons/QQ/41.gif" border="0" height="20" width="20" /><br /><br /><br />当在C中定义了一个结构类型时，它的大小是否等于各字段(field)大小之和？编译器将如何在内存中放置这<font face="Courier New" size="4">些字段？ANSI 
C对结构体的内存布局有什么要求？而我们的程序又能否依赖这种布局？这些问题或许对不少朋友</font><font face="Courier New" size="4">来说还有点模糊，那么本文就试着探究它们背后的秘密。</font><p><font face="Courier New" size="4">    首先，至少有一点可以肯定，那就是ANSI 
C保证结构体中各字段在内存中出现的位置是随它们的声明顺序依</font><font face="Courier New" size="4">次递增的，并且第一个字段的首地址等于整个结构体实例的首地址。比如有这样一个结构体：<br />  <br />  <font color="#a52a2a">struct vector{int x,y,z;} s;<br />  int *p,*q,*r;<br />  struct vector 
*ps;<br />  <br />  p = &amp;s.x;<br />  q = &amp;s.y;<br />  r = &amp;s.z;<br />  ps = 
&amp;s;</font></font></p><p><font color="#a52a2a" face="Courier New" size="4">  assert(p &lt; q);<br />  
assert(p &lt; r);<br />  assert(q &lt; r);<br />  assert((int*)ps == p);<br />  <font color="#006400">// 上述断言一定不会失败</font></font></p><p><font face="Courier New" size="4">    这时，有朋友可能会问:"标准是否规定相邻字段在内存中也相邻?"。 
唔，对不起，ANSI C没有做出保证，</font><font face="Courier New" size="4">你的程序在任何时候都不应该依赖这个假设。那这是否意味着我们永远无法勾勒出一幅更清晰更精确的结构体内</font><font face="Courier New" size="4">存布局图？哦，当然不是。不过先让我们从这个问题中暂时抽身，关注一下另一个重要问题————内存对齐。</font></p><p><font face="Courier New" size="4">    
许多实际的计算机系统对基本类型数据在内存中存放的位置有限制，它们会要求这些数据的首地址的值是某</font><font face="Courier New" size="4">个数k(通常它为4或8)的倍数，这就是所谓的内存对齐，而这个k则被称为该数据类型的对齐模数(alignment </font><font face="Courier New" size="4">modulus)。当一种类型S的对齐模数与另一种类型T的对齐模数的比值是大于1的整数，我们就称类型S的对齐要求</font><font face="Courier New" size="4">比T强(严格)，而称T比S弱(宽松)。这种强制的要求一来简化了处理器与内存之间传输系统的设计，二来可以提升</font><font face="Courier New" size="4">读取数据的速度。比如这么一种处理器，它每次读写内存的时候都从某个8倍数的地址开始，一次读出或写入8个</font><font face="Courier New" size="4">字节的数据，假如软件能保证double类型的数据都从8倍数地址开始，那么读或写一个double类型数据就只需要</font><font face="Courier New" size="4">一次内存操作。否则，我们就可能需要两次内存操作才能完成这个动作，因为数据或许恰好横跨在两个符合对齐</font><font face="Courier New" size="4">要求的8字节内存块上。某些处理器在数据不满足对齐要求的情况下可能会出错，但是Intel的IA32架构的处理器</font><font face="Courier New" size="4">则不管数据是否对齐都能正确工作。不过Intel奉劝大家，如果想提升性能，那么所有的程序数据都应该尽可能地</font><font face="Courier New" size="4">对齐。Win32平台下的微软C编译器(cl.exe for 80x86)在默认情况下采用如下的对齐规则: 
任何基本数据类型T</font><font face="Courier New" size="4">的对齐模数就是T的大小，即sizeof(T)。比如对于double类型(8字节)，就要求该类型数据的地址总是8的倍数</font><font face="Courier New" size="4">，而char类型数据(1字节)则可以从任何一个地址开始。Linux下的GCC奉行的是另外一套规则(在资料中查得，并</font><font face="Courier New" size="4">未验证，如错误请指正):任何2字节大小(包括单字节吗?)的数据类型(比如short)的对齐模数是2，而其它所有超</font><font face="Courier New" size="4">过2字节的数据类型(比如long,double)都以4为对齐模数。</font></p><p><font face="Courier New" size="4">    现在回到我们关心的struct上来。ANSI 
C规定一种结构类型的大小是它所有字段的大小以及字段之间或字段</font><font face="Courier New" size="4">尾部的填充区大小之和。嗯？填充区？对，这就是为了使结构体字段满足内存对齐要求而额外分配给结构体的空</font><font face="Courier New" size="4">间。那么结构体本身有什么对齐要求吗？有的，ANSI 
C标准规定结构体类型的对齐要求不能比它所有字段中要求</font><font face="Courier New" size="4">最严格的那个宽松，可以更严格(但此非强制要求，VC7.1就仅仅是让它们一样严格)。我们来看一个例子(以下所</font><font face="Courier New" size="4">有试验的环境是Intel Celeron 2.4G + WIN2000 PRO + 
vc7.1，内存对齐编译选项是"默认"，即不指定/Zp与</font><font face="Courier New" size="4">/pack选项):</font></p><p><font face="Courier New" size="4">  <font color="#a52a2a">typedef struct ms1<br />  
{<br />     char a;<br />     int b;<br />  } MS1;</font></font></p><p><font face="Courier New" size="4">    
假设MS1按如下方式内存布局(本文所有示意图中的内存地址从左至右递增):<br /><font color="#0000ff">       
_____________________________<br />       |       |                   |<br />       
|   a   |        b          |<br />       |       |                   |<br />       
+---------------------------+<br /> Bytes:    1             4</font></font></p><p><font face="Courier New" size="4">    
因为MS1中有最强对齐要求的是b字段(int)，所以根据编译器的对齐规则以及ANSI C标准，MS1对象的首地</font><font face="Courier New" size="4">址一定是4(int类型的对齐模数)的倍数。那么上述内存布局中的b字段能满足int类型的对齐要求吗？嗯，当然不</font><font face="Courier New" size="4">能。如果你是编译器，你会如何巧妙安排来满足CPU的癖好呢？呵呵，经过1毫秒的艰苦思考，你一定得出了如下</font><font face="Courier New" size="4">的方案：</font></p><p><font color="#0000ff" face="Courier New" size="4">       
_______________________________________<br />       |       
|\\\\\\\\\\\|                 |<br />       |   a   |\\padding\\|       b         
|<br />       |       |\\\\\\\\\\\|                 |<br />       
+-------------------------------------+<br /> Bytes:    1         3             
4</font></p><p><font face="Courier New" size="4">    
这个方案在a与b之间多分配了3个填充(padding)字节，这样当整个struct对象首地址满足4字节的对齐要求</font><font face="Courier New" size="4">时，b字段也一定能满足int型的4字节对齐规定。那么sizeof(MS1)显然就应该是8，而b字段相对于结构体首地</font><font face="Courier New" size="4">址的偏移就是4。非常好理解，对吗？现在我们把MS1中的字段交换一下顺序:</font></p><p><font face="Courier New" size="4">  <font color="#a52a2a">typedef struct ms2<br />  
{<br />     int a;<br />     char b;<br />  } MS2;</font></font></p><p><font face="Courier New" size="4">    或许你认为MS2比MS1的情况要简单，它的布局应该就是</font></p><p><font color="#0000ff" face="Courier New" size="4">       
_______________________<br />       |             |       |<br />       |     
a       |   b   |<br />       |             |       |<br />       
+---------------------+<br /> Bytes:      4           1 </font></p><p><font face="Courier New" size="4">    
因为MS2对象同样要满足4字节对齐规定，而此时a的地址与结构体的首地址相等，所以它一定也是4字节对齐</font><font face="Courier New" size="4">。嗯，分析得有道理，可是却不全面。让我们来考虑一下定义一个MS2类型的数组会出现什么问题。C标准保证，</font><font face="Courier New" size="4">任何类型(包括自定义结构类型)的数组所占空间的大小一定等于一个单独的该类型数据的大小乘以数组元素的个</font><font face="Courier New" size="4">数。换句话说，数组各元素之间不会有空隙。按照上面的方案，一个MS2数组array的布局就是:</font></p><font color="#0000ff" face="Courier New" size="4"></font><p><font color="#0000ff" face="Courier New" size="4"><font color="#0000ff" face="Courier New" size="4">|&lt;-    array[1]     
-&gt;|&lt;-    array[2]     -&gt;|&lt;- array[3] .....</font></font></p><p><font color="#0000ff" face="Courier New" size="4"><font color="#0000ff" face="Courier New" size="4">__________________________________________________________<br />|             
|       |              |      |<br />|     a       |   b   |      a       |   b  
|.............<br />|             |       |              |      
|<br />+----------------------------------------------------------<br />Bytes:  
4         1          4           1</font></font></p><p><font face="Courier New" size="4">    
当数组首地址是4字节对齐时，array[1].a也是4字节对齐，可是array[2].a呢？array[3].a ....呢？可</font><font face="Courier New" size="4">见这种方案在定义结构体数组时无法让数组中所有元素的字段都满足对齐规定，必须修改成如下形式:</font></p><p><font color="#0000ff" face="Courier New" size="4">       
___________________________________<br />       |             |       
|\\\\\\\\\\\|<br />       |     a       |   b   |\\padding\\|<br />       
|             |       |\\\\\\\\\\\|<br />       
+---------------------------------+<br /> Bytes:      4           1         
3</font></p><p><font face="Courier New" size="4">    
现在无论是定义一个单独的MS2变量还是MS2数组，均能保证所有元素的所有字段都满足对齐规定。那么</font><font face="Courier New" size="4">sizeof(MS2)仍然是8，而a的偏移为0，b的偏移是4。</font></p><p><font face="Courier New" size="4">    
好的，现在你已经掌握了结构体内存布局的基本准则，尝试分析一个稍微复杂点的类型吧。</font></p><p><font face="Courier New" size="4">  <font color="#a52a2a">typedef struct ms3<br />  
{<br />     char a;<br />     short b;<br />     double c;<br />  } 
MS3;</font></font></p><p><font face="Courier New" size="4">    我想你一定能得出如下正确的布局图:<br />         <br /><font color="#0000ff">        padding  <br />           |<br />      
_____v_________________________________<br />      |   |\|     
|\\\\\\\\\|               |<br />      | a |\|  b  |\padding\|       c       
|<br />      |   |\|     |\\\\\\\\\|               |<br />      
+-------------------------------------+<br />Bytes:  1  1   2       4            
8<br /></font>           <br />    
sizeof(short)等于2，b字段应从偶数地址开始，所以a的后面填充一个字节，而sizeof(double)等于8，c</font><font face="Courier New" size="4">字段要从8倍数地址开始，前面的a、b字段加上填充字节已经有4 
bytes，所以b后面再填充4个字节就可以保证c</font><font face="Courier New" size="4">字段的对齐要求了。sizeof(MS3)等于16，b的偏移是2，c的偏移是8。接着看看结构体中字段还是结构类型的情</font><font face="Courier New" size="4">况:</font></p><p><font face="Courier New" size="4"> <font color="#a52a2a"> typedef struct ms4<br />  
{<br />     char a;<br />     MS3 b;<br />  } MS4;</font></font></p><p><font face="Courier New" size="4">    
MS3中内存要求最严格的字段是c，那么MS3类型数据的对齐模数就与double的一致(为8)，a字段后面应填充</font><font face="Courier New" size="4">7个字节，因此MS4的布局应该是:<br /><font color="#0000ff">       
_______________________________________<br />       |       
|\\\\\\\\\\\|                 |<br />       |   a   |\\padding\\|       b         
|<br />       |       |\\\\\\\\\\\|                 |<br />       
+-------------------------------------+<br /> Bytes:    1         7             
16</font></font></p><p><font face="Courier New" size="4">    显然，sizeof(MS4)等于24，b的偏移等于8。</font></p><p><font face="Courier New" size="4">    
在实际开发中，我们可以通过指定/Zp编译选项来更改编译器的对齐规则。比如指定/Zpn(VC7.1中n可以是1</font><font face="Courier New" size="4">、2、4、8、16)就是告诉编译器最大对齐模数是n。在这种情况下，所有小于等于n字节的基本数据类型的对齐规</font><font face="Courier New" size="4">则与默认的一样，但是大于n个字节的数据类型的对齐模数被限制为n。事实上，VC7.1的默认对齐选项就相当于</font><font face="Courier New" size="4">/Zp8。仔细看看MSDN对这个选项的描述，会发现它郑重告诫了程序员不要在MIPS和Alpha平台上用/Zp1和/Zp2选</font><font face="Courier New" size="4">项，也不要在16位平台上指定/Zp4和/Zp8(想想为什么？)。改变编译器的对齐选项，对照程序运行结果重新分析</font><font face="Courier New" size="4">上面4种结构体的内存布局将是一个很好的复习。</font></p><p><font face="Courier New" size="4">    
到了这里，我们可以回答本文提出的最后一个问题了。结构体的内存布局依赖于CPU、操作系统、编译器及编</font><font face="Courier New" size="4">译时的对齐选项，而你的程序可能需要运行在多种平台上，你的源代码可能要被不同的人用不同的编译器编译(试</font><font face="Courier New" size="4">想你为别人提供一个开放源码的库)，那么除非绝对必需，否则你的程序永远也不要依赖这些诡异的内存布局。顺</font><font face="Courier New" size="4">便说一下，如果一个程序中的两个模块是用不同的对齐选项分别编译的，那么它很可能会产生一些非常微妙的错</font><font face="Courier New" size="4">误。如果你的程序确实有很难理解的行为，不防仔细检查一下各个模块的编译选项。</font></p><p><font face="Courier New" size="4">    
思考题:请分析下面几种结构体在你的平台上的内存布局，并试着寻找一种合理安排字段声明顺序的方法以尽</font><font face="Courier New" size="4">量节省内存空间。</font></p><p><font face="Courier New" size="4">    A. <font color="#a52a2a">struct P1 { int a; 
char b; int c; char d; };<br /></font>    B. <font color="#a52a2a">struct P2 { int 
a; char b; char c; int d; };</font><br />    C. <font color="#a52a2a">struct P3 { 
short a[3]; char b[3]; };<br /></font>    D. <font color="#a52a2a">struct P4 { short 
a[3]; char *b[3]; };<br /></font>    E. <font color="#a52a2a">struct P5 { struct P2 
*a; char b; struct P1 a[2];  };</font></font></p><p><font face="Courier New" size="4">参考资料:</font></p><p><font face="Courier New" size="4">    【1】《深入理解计算机系统(修订版)》，<br />         
(著)Randal E.Bryant; David O'Hallaron，<br />         (译)龚奕利 雷迎春，<br />         
中国电力出版社，2004<br />    <br />    【2】《C: A Reference Manual》(影印版)，<br />         
(著)Samuel P.Harbison; Guy L.Steele，<br />         人民邮电出版社，2003<br /></font></p><img src ="http://www.cppblog.com/saga/aggbug/7774.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/saga/" target="_blank">saga.constantine</a> 2006-05-28 16:15 <a href="http://www.cppblog.com/saga/archive/2006/05/28/7774.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[截图]关于结构体的数据对齐（Structure Alignment Examples  ）</title><link>http://www.cppblog.com/saga/archive/2006/05/27/7723.html</link><dc:creator>saga.constantine</dc:creator><author>saga.constantine</author><pubDate>Sat, 27 May 2006 05:06:00 GMT</pubDate><guid>http://www.cppblog.com/saga/archive/2006/05/27/7723.html</guid><wfw:comment>http://www.cppblog.com/saga/comments/7723.html</wfw:comment><comments>http://www.cppblog.com/saga/archive/2006/05/27/7723.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/saga/comments/commentRss/7723.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/saga/services/trackbacks/7723.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal">
				<span style="FONT-FAMILY: 宋体">从</span>
				<span lang="EN-US">MSND</span>
				<span style="FONT-FAMILY: 宋体">上截下来的，帮助理解数据对齐。</span>
				<span lang="EN-US">
						<br />
				</span>
				<span style="FONT-FAMILY: 宋体">编译出来的结构体怎么占用内存的。</span>
				<span lang="EN-US">padding</span>
				<span style="FONT-FAMILY: 宋体">为编译器填充的，不理解的可以看看我前面发的翻译的关于数据对齐～</span>
				<img border="0" height="19" src="http://www.cppblog.com/Emoticons/QQ/22.gif" width="19" />
				<br />
				<span lang="EN-US">
						<v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">
								<v:stroke joinstyle="miter">
										<v:formulas>
												<v:f eqn="if lineDrawn pixelLineWidth 0">
														<v:f eqn="sum @0 1 0">
																<v:f eqn="sum 0 0 @1">
																		<v:f eqn="prod @2 1 2">
																				<v:f eqn="prod @3 21600 pixelWidth">
																						<v:f eqn="prod @3 21600 pixelHeight">
																								<v:f eqn="sum @0 0 1">
																										<v:f eqn="prod @6 1 2">
																												<v:f eqn="prod @7 21600 pixelWidth">
																														<v:f eqn="sum @8 21600 0">
																																<v:f eqn="prod @7 21600 pixelHeight">
																																		<v:f eqn="sum @10 21600 0">
																																		</v:f>
																																</v:f>
																														</v:f>
																												</v:f>
																										</v:f>
																								</v:f>
																						</v:f>
																				</v:f>
																		</v:f>
																</v:f>
														</v:f>
												</v:f>
										</v:formulas>
										<v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect">
												<o:lock v:ext="edit" aspectratio="t">
												</o:lock>
										</v:path>
								</v:stroke>
						</v:shapetype>
				</span>
				<span lang="EN-US" style="FONT-FAMILY: Verdana; FONT-SIZE: 10pt">alignment   </span>
				<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10pt">对齐；</span>
				<span lang="EN-US" style="FONT-FAMILY: Verdana; FONT-SIZE: 10pt">Quadword </span>
				<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10pt">＝</span>
				<span lang="EN-US" style="FONT-FAMILY: Verdana; FONT-SIZE: 10pt">8 byte </span>
				<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10pt">；</span>
				<span lang="EN-US" style="FONT-FAMILY: Verdana; FONT-SIZE: 10pt">Doubleword </span>
				<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10pt">＝</span>
				<span lang="EN-US" style="FONT-FAMILY: Verdana; FONT-SIZE: 10pt">4 byte<br /><img alt="对齐.BMP" border="0" height="127" src="http://www.cppblog.com/images/cppblog_com/saga/%E5%AF%B9%E9%BD%90.BMP" width="400" /></span>
				<span lang="EN-US">
						<br />
				</span>
				<span style="FONT-FAMILY: 宋体">－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－</span>
				<span lang="EN-US">
						<br />
						<br />
				</span>
				<span lang="EN-US" style="FONT-FAMILY: Verdana; FONT-SIZE: 10pt">Example 2</span>
				<span lang="EN-US" style="FONT-FAMILY: Verdana; FONT-SIZE: 7.5pt">
						<br />
				</span>
				<span lang="EN-US" style="FONT-FAMILY: Verdana; FONT-SIZE: 10pt">
						<img alt="对齐2.BMP" border="0" height="133" src="http://www.cppblog.com/images/cppblog_com/saga/%E5%AF%B9%E9%BD%902.BMP" width="460" />
						<br />
				</span>
				<span style="FONT-FAMILY: 宋体">－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－</span>
				<span lang="EN-US">
						<img alt="对齐3.BMP" border="0" height="170" src="http://www.cppblog.com/images/cppblog_com/saga/%E5%AF%B9%E9%BD%903.BMP" width="453" />
						<br />
						<br />
				</span>
				<span style="FONT-FAMILY: 宋体">－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－</span>
				<span lang="EN-US">
						<br />
						<v:shape id="_x0000_i1029" style="HEIGHT: 157.5pt; WIDTH: 285.75pt" type="#_x0000_t75" alt="对齐4.BMP">
								<br />     <img alt="对齐4.BMP" border="0" height="210" src="http://www.cppblog.com/images/cppblog_com/saga/%E5%AF%B9%E9%BD%904.BMP" width="381" />                                                                                                                                                                                                   </v:shape>
				</span>
				<span style="FONT-FAMILY: 宋体">－－－－</span>
				<span lang="EN-US">saga.constantine</span>
		</p>
<img src ="http://www.cppblog.com/saga/aggbug/7723.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/saga/" target="_blank">saga.constantine</a> 2006-05-27 13:06 <a href="http://www.cppblog.com/saga/archive/2006/05/27/7723.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[翻译]关于数据对齐（About Data Alignment）</title><link>http://www.cppblog.com/saga/archive/2006/05/26/7674.html</link><dc:creator>saga.constantine</dc:creator><author>saga.constantine</author><pubDate>Fri, 26 May 2006 02:41:00 GMT</pubDate><guid>http://www.cppblog.com/saga/archive/2006/05/26/7674.html</guid><wfw:comment>http://www.cppblog.com/saga/comments/7674.html</wfw:comment><comments>http://www.cppblog.com/saga/archive/2006/05/26/7674.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/saga/comments/commentRss/7674.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/saga/services/trackbacks/7674.html</trackback:ping><description><![CDATA[
		<p>
				<font size="4">
						<font face="Arial">
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">练习一下翻译能力！不当之处请指出！！</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">
								</span>
						</font>
				</font>
				<br />
				<font size="4">
						<font face="Arial">
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">原文出自</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">MSDN</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">，链接为</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">
								</span>
						</font>
				</font>
				<a href="http://msdn2.microsoft.com/en-us/library/ms253949.aspx">
						<font face="Arial" size="4">http://msdn2.microsoft.com/en-us/library/ms253949.aspx</font>
				</a>
				<br />
				<br />
				<font face="Arial" size="4">       </font>
				<font size="4">
						<font face="Arial">
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">很多</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">CPU</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">，如基于</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">Alpha, IA-64, MIPS, </span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">和</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">SuperH </span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">体系的，拒绝读取未对齐数据。当一个程序要求其中之一的</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">CPU</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">读取未对齐数据时，这时</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">CPU</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">会进入异常处理状态并且通知程序不能继续执行。举个例子，在</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">ARM, MIPS, </span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">和</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">SH</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">硬件平台上，当操作系统被要求存取一个未对齐数据时默认通知应用程序一个异常。</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">
								</span>
						</font>
				</font>
				<br />
				<br />
				<font size="4">
						<font face="Arial">
								<strong>
										<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">对齐性</span>
								</strong>
								<b>
								</b>
						</font>
				</font>
				<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">
						<br />
						<font face="Arial" size="4">
								<strong>     </strong>
						</font>
				</span>
				<font size="4">
						<font face="Arial">
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">  </span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">对齐性是一种内存地址的特性，表现为内存地址模上</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">2</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">的幂。例如，内存地址</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">0x0001103F</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">模</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">4</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">结果为</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">3</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">；这个地址就叫做与</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">4n</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">＋</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">3</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">对齐，</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">4</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">指出了所选用的</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">2</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">的幂的值。内存地址的对齐性取决于所选择的关于</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">2</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">的幂值。同样的地址模</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">8</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">结果为</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">7</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">。</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">
								</span>
						</font>
				</font>
				<br />
				<br />
				<font face="Arial" size="4">       </font>
				<font size="4">
						<font face="Arial">
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">一个内存地址符合表达式</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">Xn</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">＋</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">0</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">，那么就说该地址对齐于</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">X</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">。</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">
								</span>
						</font>
				</font>
				<br />
				<br />
				<font face="Arial" size="4">       <span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">CPU</span></font>
				<font size="4">
						<font face="Arial">
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">执行指令就是对存储于内存上的数据进行操作，这些数据在内存上是以地址为标记的。对于地址来说，单独的数据会有其占用内存的字节数。如果它的地址对齐于它的字节数，那么就称作该数据自然对齐，否则称为未对齐。例如，一个标记</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">8</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">字节的浮点数据的地址对齐于</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">8</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">，那么这个数据就自然对齐。</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">
								</span>
						</font>
				</font>
				<br />
				<br />
				<font size="4">
						<font face="Arial">
								<strong>
										<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">数据对齐性的编译处理</span>
								</strong>
								<b>
								</b>
						</font>
				</font>
				<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">
						<br />
						<font face="Arial" size="4">
								<strong>       </strong>
						</font>
				</span>
				<font size="4">
						<font face="Arial">
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">设备编译器以一种防止造成数据未对齐的方式来对数据进行地址分配。</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">
								</span>
						</font>
				</font>
				<br />
				<br />
				<font face="Arial" size="4">       </font>
				<font size="4">
						<font face="Arial">
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">对于单个的数据类型，编译器为其分配的地址是数据类型字节数的倍数。因此，编译器分配给</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">long</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">型变量的地址为</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">4</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">的倍数，就是说以</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">2</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">进制表示地址的话，最后两位为</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">0</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">。</span>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">
								</span>
						</font>
				</font>
				<br />
				<br />
				<font face="Arial" size="4">       </font>
				<font face="Arial">
						<font size="4">
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">另外，编译器以一种自然对齐每个结构成员的方式来填充结构体。参看下面的代码里面的结构体</span>
								<b>
										<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">struct x_</span>
								</b>
								<span lang="EN-US" style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">
								</span>
								<span style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">。<br /><br />     <font face="Verdana">struct x_<br />      {<br />            char a;     // 1 byte<br />            int b;      // 4 bytes<br />            short c;    // 2 bytes<br />            char d;     // 1 byte<br />      } MyStruct;<br /><br />      编译器填充这个结构以使其自然对齐。<br /><br /><strong>例如<br /></strong>      下面的代码说明了编译器是如何在内存中填充的。<br /><br />      // Shows the actual memory layout<br />      struct x_<br />     {<br />           char a;            // 1 byte<br />           char _pad0[3];     // padding to put 'b' on 4-byte boundary<br />           int b;            // 4 bytes<br />           short c;          // 2 bytes<br />           char d;           // 1 byte<br />           char _pad1[1];    // padding to make sizeof(x_) multiple of 4<br />     }<br /><br />     两种定义在作</font><font face="Times New Roman"><strong><b>sizeof(struct x_)</b></strong>运算都会返回12字节。<br /><br />      第二种定义含有两种填充成分：<br /><br />             *<b>char _pad0[3]</b>使得<b>int</b> b 在4字节边界上对齐<br /><br />             *<strong>char _pad1[1]</strong>使得结构数组<strong>struct _x  bar[3]</strong>对齐。<br />             填充使得<strong><b>bar[3]</b></strong>各个变量能够自然对齐。<br /><font face=""><br />             下面的代码显示了<strong><b>bar[3]</b></strong>的内存结构：<br /><br />              <span lang="EN-US" style="FONT-FAMILY: Verdana; FONT-SIZE: 10.5pt; mso-bidi-font-size: 12.0pt; mso-bidi-font-family: 'Times New Roman'; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">adr<br />              offset   element<br />------   -------<br />0x0000   char a;         // bar[0]<br />0x0001   char pad0[3];<br />0x0004   int b;<br />0x0008   short c;<br />0x000a   char d;<br />0x000b   char _pad1[1];<br /><br />0x000c   char a;         // bar[1]<br />0x000d   char _pad0[3];<br />0x0010   int b;<br />0x0014   short c;<br />0x0016   char d;<br />0x0017   char _pad1[1];<br /><br />0x0018   char a;         // bar[2]<br />0x0019   char _pad0[3];<br />0x001c    int b;<br />0x0020   short c;<br />0x0022   char d;<br />0x0023   char _pad1[1];</span></font></font></span>
						</font>
				</font>
		</p>
		<p>
				<br />
		</p>
<img src ="http://www.cppblog.com/saga/aggbug/7674.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/saga/" target="_blank">saga.constantine</a> 2006-05-26 10:41 <a href="http://www.cppblog.com/saga/archive/2006/05/26/7674.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转贴]一个中国黑客致中国黑客和红客的公开信</title><link>http://www.cppblog.com/saga/archive/2006/05/25/7658.html</link><dc:creator>saga.constantine</dc:creator><author>saga.constantine</author><pubDate>Thu, 25 May 2006 14:20:00 GMT</pubDate><guid>http://www.cppblog.com/saga/archive/2006/05/25/7658.html</guid><wfw:comment>http://www.cppblog.com/saga/comments/7658.html</wfw:comment><comments>http://www.cppblog.com/saga/archive/2006/05/25/7658.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/saga/comments/commentRss/7658.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/saga/services/trackbacks/7658.html</trackback:ping><description><![CDATA[
		<h1>转<img border="0" height="19" src="http://www.cppblog.com/Emoticons/car.gif" width="19" />转贴！<br /><br />所有中国黑客和红客，我的同胞们： <br />首先声明，我的计算机软件技术、黑客功底，可能不会比你们任何人差： </h1>
		<div>我通读过 MINIX，TCP/IP，BSD,LINUX, PL1的源码，我拿过中国高级程序员证书，SUN 的JAVA证书，精通VC和UNIX，对缓冲区溢出，病毒，DDK等均有研究，所以我想我有资格对你们说几句话。 </div>
		<div>(如果我提到的一些计算机名词和人名，你们居然不知道，那只能证明你们的无知，和不配称为黑客。) </div>
		<div>如果是真正的黑客，他会知道 </div>
		<div>1.发明TCP/IP的是美国人 。 </div>
		<div>2. LINUX的作者，linus大侠现在也在美国工作 。 </div>
		<div>3. OPEN SOURCE的开创人 STALLMAN 也是美国人，他提倡软件不分国界的自由的精神 。 </div>
		<div>4. FREE BSD 的作者是美国人，他的SOURCE 让真正的黑客受惠 </div>
		<div>5.世界级软件科学大师 tanabaom，也是美国的客座教授，他的minix, ameba和教材教育了全世界几代黑客。 </div>
		<div>提到这些，不是崇美，不是恐美，只想证明： </div>
		<div>1.很多大师级的美国黑客，他们的理念恰恰是自由、开放、无国界；他们的自由软件，开放源码，是与政治无关的，是超越国界的，给全世界人们带来福音。 </div>
		<div>2.真正的黑客精神，如stallman所说，是要让人类超越计算机，成为计算机的主宰，从而成为自由的。 </div>
		<div>所有的中国黑客和红客，我的同胞们： </div>
		<div>当你们正通过下载美国人写的黑客工具，来攻击美国网络，并且乐此不疲，以为这就是爱国行动的时候，是否想过： </div>
		<div>此时此刻，印度的软件人士，正在努力提高软件技术，他们的软件水平、软件产业已经超越了中国；难道我们不应该痛苦地承认这个现实，并且奋起直追吗？ </div>
		<div>中国发明了火药，但是缺少研究精神，结果是被西方人研究改进了以后打中国，这样的教训还少吗？ </div>
		<div>中国向来不缺爱国热情，但是我们缺少对科技的认真研究精神，知耻而后勇的追赶精神。难道我们不愿意承认这一点吗？ </div>
		<div>从战术上来说，过早暴露自己的实力是不聪明的；冒昧地问一句，如果真的战争爆发了，您的黑客技术完全掌握好了吗，您已经为那一天的到来在进行技术储备吗？ </div>
		<div>您有没有想向那些真正为中国科技做出杰出贡献的科学家如钱学森学习呢？ </div>
		<div>所有的中国黑客和红客，我的同胞们： </div>
		<div>请把你们的聪明才智用到真正提高你们的水平，对国家的强大有帮助的地方吧： </div>
		<div>如果您愿意对国家有所贡献： </div>
		<div>1.中国的863计划中有一个重点研究项目： 并行计算，分布计算，向量计算。您愿意研究它吗？ </div>
		<div>2. 作为现代通讯技术的一个根本数学基础，大合数的快速因子分解，还是一个难题。您愿意研究它吗？ </div>
		<div>如果您想提高技术，对中国的软件技术有所贡献： </div>
		<div>1.研究 VC，JAVA </div>
		<div>2.研究数据结构，去考高级程序员 </div>
		<div>3. 研究操作系统，读minix source code </div>
		<div>4. 研究tcp/ip, rfc文档 </div>
		<div>5. 通读linux, 才算达到黑客境界 </div>
		<div>6. 学习 UML，ROSE，软件工程，达到系统分析员水平。 </div>
		<div>如果您对提高中国的科技有兴趣，计算机技术，航天技术…… </div>
		<div>我的同胞们，我愿大声呐喊： </div>
		<div>一个真正的民族主义者，不是义和团，不是太平天国，不是闭关锁国，不是盲目仇外，不是不敢正视自己民族和文化的丑陋和缺点。 </div>
		<div>真正的民族主义者是成熟的、清醒的、理智的、务实的民族主义。真正的民族主义者不是种族主义者，不是极端份子，不是战争狂人。 </div>
		<div>真正的民族主义者以追求本民族——中华民族的利益最大化为目标、准则、信念。判断一个人是不是真正的民族主义者，判断标准很简单：看他是给本民族的整体利益带来好处，还是损害民族利益。真正的民族主义者最务实，因为他知道坚持原则，同时又懂得策略。让我们成为真正的顶尖黑客！让我们成为真正的民族主义者!</div>
<img src ="http://www.cppblog.com/saga/aggbug/7658.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/saga/" target="_blank">saga.constantine</a> 2006-05-25 22:20 <a href="http://www.cppblog.com/saga/archive/2006/05/25/7658.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>