<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_SweetDream</title><subtitle type="text">高歌一壶新酿酒，醉抱青山不必归。</subtitle><id>http://feed.cnblogs.com/blog/u/14895/rss</id><updated>2011-06-03T16:19:20Z</updated><author><name>SweetDream</name><uri>http://www.cnblogs.com/SweetDream/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SweetDream/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/14895/rss"/><entry><id>http://www.cnblogs.com/SweetDream/archive/2011/06/04/2072382.html</id><title type="text">如何使用SecureCRT连接ubuntu (转)</title><summary type="text">用secureCRT连接Ubuntu是出现远程系统拒绝访问。。经过一翻研究才知道Ubuntu上没有ssh..一下为连接过程。1. 首先要明白什么是ssh?可以把ssh看做是telnet的加强版，telnet的密码和信息都是不加密的，而ssh则加密。.2. 开启ubuntu上的ssh功能先安装，安装后就自动开启了.sudo apt-get install openssh-server openssh-client.3. 安装secureCRT.4. 查看ubuntu的ipifconfig(注意是ifconfig,不是windows上的ipconfig).5. 连接secureCRT =&gt; </summary><published>2011-06-03T16:19:00Z</published><updated>2011-06-03T16:19:00Z</updated><author><name>SweetDream</name><uri>http://www.cnblogs.com/SweetDream/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SweetDream/archive/2011/06/04/2072382.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SweetDream/archive/2011/06/04/2072382.html"/><content type="html">&lt;div&gt;&lt;span style="color: #333333; font-family: Arial, Helvetica, simsun, u5b8bu4f53; line-height: 22px; "&gt;&lt;p&gt;用secureCRT连接Ubuntu是出现远程系统拒绝访问。。经过一翻研究才知道Ubuntu上没有ssh..&lt;/p&gt;&lt;p&gt;一下为连接过程。&lt;/p&gt;&lt;p&gt;1. 首先要明白什么是ssh?&lt;/p&gt;&lt;p&gt;可以把ssh看做是telnet的加强版，telnet的密码和信息都是不加密的，而ssh则加密。&lt;/p&gt;&lt;p&gt;.&lt;br style="line-height: 22px; " /&gt;2. 开启ubuntu上的ssh功能&lt;/p&gt;&lt;p&gt;先安装，安装后就自动开启了.&lt;/p&gt;&lt;p&gt;sudo apt-get install openssh-server openssh-client&lt;/p&gt;&lt;p&gt;.&lt;/p&gt;&lt;p&gt;3. 安装secureCRT&lt;/p&gt;&lt;p&gt;.&lt;br style="line-height: 22px; " /&gt;4. 查看ubuntu的ip&lt;/p&gt;&lt;p&gt;ifconfig(注意是ifconfig,不是windows上的ipconfig)&lt;/p&gt;&lt;p&gt;.&lt;br style="line-height: 22px; " /&gt;5. 连接&lt;/p&gt;&lt;p&gt;secureCRT =&amp;gt; Quick Connect, 连接ubuntu, 输入ubuntu的id和pwd&lt;/p&gt;&lt;p&gt;.（如果还连接不上，可能是Ubuntu上的ssh服务没有开启。&lt;/p&gt;&lt;p&gt;. 启动ssh-server。&lt;br style="line-height: 22px; " /&gt;$ /etc/init.d/ssh restart&lt;br style="line-height: 22px; " /&gt;&lt;br style="line-height: 22px; " /&gt;. 确认ssh-server已经正常工作。&lt;br style="line-height: 22px; " /&gt;$ netstat -tlp&lt;br style="line-height: 22px; " /&gt;tcp6 &amp;nbsp;&amp;nbsp; 0 &amp;nbsp;&amp;nbsp; 0 *:ssh &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; *:* &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; LISTEN &amp;nbsp;&amp;nbsp;&amp;nbsp; -&lt;br style="line-height: 22px; " /&gt;看到上面这一行输出说明ssh-server已经在运行了。&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/SweetDream/aggbug/2072382.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/SweetDream/archive/2011/06/04/2072382.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/SweetDream/archive/2011/04/27/2031225.html</id><title type="text">转 linux共享</title><summary type="text">安装samba：sudo apt-get install sambasudo apt-get install smbfs下面我们来共享群组可读写文件夹，假设你要共享的文件夹为： /home/ray/share首先创建这个文件夹mkdir /home/ray/sharechmod 777 /home/ray/share备份并编辑smb.conf允许网络用户访问sudo cp /etc/samba/smb.conf /etc/samba/smb.conf_backupsudo gedit /etc/samba/smb.conf搜寻这一行文字;security = user用下面这几行取代secur</summary><published>2011-04-27T15:21:00Z</published><updated>2011-04-27T15:21:00Z</updated><author><name>SweetDream</name><uri>http://www.cnblogs.com/SweetDream/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SweetDream/archive/2011/04/27/2031225.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SweetDream/archive/2011/04/27/2031225.html"/><content type="html">&lt;div&gt;&lt;span style="color: #4e4e4e; font-size: 13px; font-family: Georgia, 'Nimbus Roman No9 L', serif; line-height: normal; "&gt;&lt;p&gt;安装samba：&lt;/p&gt;&lt;p&gt;sudo apt-get install samba&lt;/p&gt;&lt;p&gt;sudo apt-get install smbfs&lt;/p&gt;&lt;p&gt;下面我们来共享群组可读写文件夹，假设你要共享的文件夹为： /home/ray/share&lt;/p&gt;&lt;p&gt;首先创建这个文件夹&lt;/p&gt;&lt;p&gt;mkdir /home/ray/share&lt;/p&gt;&lt;p&gt;chmod 777 /home/ray/share&lt;/p&gt;&lt;p&gt;备份并编辑smb.conf允许网络用户访问&lt;/p&gt;&lt;p&gt;sudo cp /etc/samba/smb.conf /etc/samba/smb.conf_backup&lt;/p&gt;&lt;p&gt;sudo gedit /etc/samba/smb.conf&lt;/p&gt;&lt;p&gt;搜寻这一行文字&lt;/p&gt;&lt;p&gt;;security = user&lt;/p&gt;&lt;p&gt;用下面这几行取代&lt;/p&gt;&lt;p&gt;security = user&lt;/p&gt;&lt;p&gt;username map = /etc/samba/smbusers&lt;/p&gt;&lt;p&gt;&lt;span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-family: Georgia, 'Nimbus Roman No9 L', serif; color: #ff0000; "&gt;&lt;span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-family: Georgia, 'Nimbus Roman No9 L', serif; color: #888888; "&gt;若要使用用户可以匿名访问到，用下面这一行取代：&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; font-family: Georgia, 'Nimbus Roman No9 L', serif; color: #888888; "&gt;security = share&lt;/span&gt;&lt;/p&gt;&lt;p&gt;将下列几行新增到文件的最后面，假设允许访问的用户为：youuser。而文件夹的共享名为 Share&lt;/p&gt;&lt;p&gt;[Share]&lt;/p&gt;&lt;p&gt;comment = Shared Folder with username and password&lt;/p&gt;&lt;p&gt;path = /home/ray/share&lt;/p&gt;&lt;p&gt;public = yes&lt;/p&gt;&lt;p&gt;writable = yes&lt;/p&gt;&lt;p&gt;valid users = youuser&lt;/p&gt;&lt;p&gt;create mask = 0700&lt;/p&gt;&lt;p&gt;directory mask = 0700&lt;/p&gt;&lt;p&gt;force user = nobody&lt;/p&gt;&lt;p&gt;force group = nogroup&lt;/p&gt;&lt;p&gt;available = yes&lt;/p&gt;&lt;p&gt;browseable = yes&lt;/p&gt;&lt;p&gt;然后顺便把这里改一下，找到[global]把 workgroup = MSHOME 改成&lt;/p&gt;&lt;p&gt;workgroup = WORKGROUP&lt;/p&gt;&lt;p&gt;display charset = UTF-8&lt;/p&gt;&lt;p&gt;unix charset = UTF-8&lt;/p&gt;&lt;p&gt;dos charset = cp936&lt;/p&gt;&lt;p&gt;后面的三行是为了防止出现中文目录乱码的情况。其中根据你的local，UTF-8 有可能需要改成 cp936。自己看着办吧。&lt;/p&gt;&lt;p&gt;现在要添加youuser这个网络访问帐户。如果系统中当前没有这个帐户，那么&lt;/p&gt;&lt;p&gt;sudo useradd youuser&lt;/p&gt;&lt;p&gt;要注意，上面只是增加了youuser这个用户，却没有给用户赋予本机登录密码。所以这个用户将只能从远程访问，不能从本机登录。而且samba的登录密码可以和本机登录密码不一样。&lt;/p&gt;&lt;p&gt;现在要新增网络使用者的帐号：&lt;/p&gt;&lt;p&gt;sudo smbpasswd -a youuser&lt;/p&gt;&lt;p&gt;sudo gedit /etc/samba/smbusers&lt;/p&gt;&lt;p&gt;在新建立的文件内加入下面这一行并保存&lt;/p&gt;&lt;p&gt;youuser = &amp;#8220;network username&amp;#8221;&lt;/p&gt;&lt;p&gt;如果将来需要更改youuser的网络访问密码，也用这个命令更改&lt;/p&gt;&lt;p&gt;sudo smbpasswd -a youuser&lt;/p&gt;&lt;p&gt;删除网络使用者的帐号的命令把上面的 -a 改成 -x&lt;/p&gt;&lt;p&gt;sudo testparm&lt;/p&gt;&lt;p&gt;sudo /etc/init.d/samba restart&lt;/p&gt;&lt;p&gt;重启下samba服务。&lt;/p&gt;&lt;p&gt;windows 输入你的ip输入用户名和密码就能访问了。&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/SweetDream/aggbug/2031225.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/SweetDream/archive/2011/04/27/2031225.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/SweetDream/archive/2010/12/24/1915667.html</id><title type="text">VC++中的char,wchar_t,TCHAR(转载)</title><summary type="text">总体简介：由于字符编码的不同，在C++中有三种对于字符类型：char, wchar_t , TCHAR。其实TCHAR不能算作一种类型，他紧紧是一个宏。我们都知道，宏在预编译的时候会被替换成相应的内容。TCHAR 在使用多字节编码时被定义成char，在Unicode编码时定义成wchar_t。1.VC++中的char,wchar_t,TCHAR大家一起做一个项目，经常发现有的人爱用strcpy等标准ANSI函数，有的人爱用_tXXXX函数，这个问题曾经搞的很混乱。为了统一，有必要把来龙去脉搞清楚。为了搞清这些函数，就必须理请几种字符类型的写法。char就不用说了，先说一些wchar_t。wch</summary><published>2010-12-24T02:30:00Z</published><updated>2010-12-24T02:30:00Z</updated><author><name>SweetDream</name><uri>http://www.cnblogs.com/SweetDream/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SweetDream/archive/2010/12/24/1915667.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SweetDream/archive/2010/12/24/1915667.html"/><content type="html">&lt;div&gt;&lt;span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: normal; "&gt;&lt;p&gt;总体简介：&lt;br /&gt;由于字符编码的不同，在C++中有三种对于字符类型：char, wchar_t , TCHAR。其实TCHAR不能算作一种类型，他紧紧是一个宏。我们都知道，宏在预编译的时候会被替换成相应的内容。TCHAR 在使用多字节编码时被定义成char，在Unicode编码时定义成wchar_t。&lt;/p&gt;&lt;div fc05="" fc11="" nbw-blog="" ztag=""  js-fs2"=""&gt;&lt;p&gt;&lt;u&gt;1.VC++中的char,wchar_t,TCHAR&lt;/u&gt;&amp;nbsp;&lt;br /&gt;大家一起做一个项目，经常发现有的人爱用strcpy等标准ANSI函数，有的人爱用_tXXXX函数，这个问题曾经搞的很混乱。为了统一，有必要把来龙去脉搞清楚。&lt;/p&gt;&lt;p&gt;&amp;nbsp;为了搞清这些函数，就必须理请几种字符类型的写法。char就不用说了，先说一些wchar_t。wchar_t是Unicode字符的数据类型，它实际定义在&amp;lt;string.h&amp;gt;里：&lt;br /&gt;&amp;nbsp;typedef unsigned short wchar_t;&lt;br /&gt;不能使用类似 strcpy这样的ANSI C字符串函数来处理wchar_t字符串，必须使用wcs前缀的函数，例如wcscpy。为了让编译器识别Unicode字符串，必须以在前面加一个 &amp;#8220;L&amp;#8221;,例如:&lt;br /&gt;&amp;nbsp;wchar_t *szTest=L"This is a Unicode string.";&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;strong&gt;下面在看看TCHAR。如果你希望同时为ANSI和Unicode编译的源代码，那就要include TChar.h&lt;/strong&gt;。TCHAR是定义在其中的一个宏，它视你是否定义了_UNICODE宏而定义成char或者wchar_t。如果你使用了TCHAR，那么就不应该使用ANSI的strXXX函数或者Unicode的wcsXXX函数了，而必须使用TChar.h中定义的_tcsXXX函数。另外，为了解决刚才提到带&amp;#8220;L&amp;#8221;的问题，TChar.h中定义了一个宏：&amp;#8220;_TEXT&amp;#8221;。&lt;/p&gt;&lt;p&gt;&amp;nbsp;以strcpy函数为例子，总结一下:&lt;br /&gt;&amp;nbsp;.如果你想使用ANSI字符串，那么请使用这一套写法：&lt;br /&gt;&amp;nbsp;char szString[100];&lt;br /&gt;&amp;nbsp;strcpy(szString,"test");&lt;br /&gt;&amp;nbsp;.如果你想使用Unicode字符串，那么请使用这一套：&lt;br /&gt;&amp;nbsp;wchar_t szString[100];&lt;br /&gt;&amp;nbsp;wcscpyszString,L"test");&lt;br /&gt;&amp;nbsp;.如果你想通过定义_UNICODE宏，而编译ANSI或者Unicode字符串代码：&lt;br /&gt;&amp;nbsp;TCHAR szString[100];&lt;br /&gt;&amp;nbsp;_tcscpy(szString,_TEXT("test"));&lt;/p&gt;&lt;p&gt;&lt;u&gt;2.&lt;/u&gt;&lt;a href="http://blog.csdn.net/white_cpf/archive/2006/04/11/658756.aspx" target="_blank" style="color: #0066aa; text-decoration: none; "&gt;字符串及处理之三: 使用TCHAR系列方案&lt;/a&gt;&lt;br /&gt;使用TCHAR系列方案编写程序&lt;br /&gt;TCHAR是一种字符串类型，它让你在以MBCS和UNNICODE来build程序时可以使用同样的代码，不需要使用繁琐的宏定义来包含你的代码。&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TCHAR的引入，主要是在Tchar.h文件中,该文件包含这方面的重要的定义信息。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 对于包含了对str函数或wcs函数进行显式调用的代码来说，无法非常容易地同时为ANSI和Unicode对这些代码进行编译。本章前面说过，可以创建同时为ANSI和Unicode进行编译的单个源代码文件。若要建立双重功能，必须包含TChar.h文件，而不是包含String.h文件。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TChar.h文件的唯一作用是帮助创建ANSI/Unicode通用源代码文件。它包含你应该用在源代码中的一组宏，而不应该直接调用str函数或者 wcs函数。如果在编译源代码文件时定义了_UNICODE，这些宏就会引用wcs这组函数。如果没有定义_UNICODE，那么这些宏将引用str这组宏。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TCHAR的定义如下：&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #ifdef UNICODE&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; typedef wchar_t TCHAR;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; typedef char TCHAR;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endif&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 所以用MBCS来build时，TCHAR是char，使用UNICODE时，TCHAR是wchar_t。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 还有一个宏来处理定义Unicode字符串常量时所需的L前缀。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #ifdef UNICODE&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #define _T(x) L##x&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #define _TEXT(x) L##x&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #define __T(x) L##x&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #define _T(x) x&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #define _TEXT(x) x&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #define __T(x) x&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #endif&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ## 是一个预处理操作符，它可以把两个参数连在一起。如果你的代码中需要字符串常量，在它前面加上_T宏。如果你使用Unicode来build，它会在字符串常量前加上L前缀。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TCHAR szNewText[] = _T("we love Bob!");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _UNICODE宏用于C运行期头文件，而UNICODE宏则用于Windows头文件。当编译源代码模块时，通常必须同时定义这两个宏。&lt;br /&gt;像是用宏来隐藏SetWindowTextA/W的细节一样，还有很多可以供你使用的宏来实现str***()和_mbs***()等字符串函数。例如，你可以使用_tcsrchr宏来替换strrchr()、_mbsrchr()和wcsrchr()。_tcsrchr根据你预定义的宏是_MBCS还是 UNICODE来扩展成正确的函数，就象SetWindowText所作的一样。&lt;br /&gt;&amp;nbsp; &amp;nbsp;不仅str***()函数有TCHAR宏。其他的函数如， _stprintf（代替sprinft()和swprintf()）,_tfopen（代替fopen()和_wfopen()）。 MSDN中"Generic-Text Routine Mappings."标题下有完整的宏列表。&lt;/p&gt;&lt;p&gt;&lt;u&gt;3.字符串及处理之二: 基本字符串类型及函数&amp;nbsp;&lt;br /&gt;&lt;/u&gt;常用的字符串类型有：char * ，wchar_t * ，WCHAR * ， TCHAR *&lt;br /&gt;char *&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 最基本的类型，其对应的一组处理函数是以str...开头的标准的ANSI C字符串函数。&lt;br /&gt;wchar_t *&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 是这样定义的：typedef unsigned short wchar_t;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 另外，在头文件中有这样的定义：typedef wchar_t WCHAR; 所以WCHAR实际就是wchar_t&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; wchar_t * 是16-bit UNICODE character（宽字符）所使用的基本类型。&lt;br /&gt;其对应的一组处理函数是以wcs...开头的标准的字符串函数。&lt;br /&gt;&lt;br /&gt;常用的字符串处理函数和宏:&amp;nbsp;&lt;br /&gt;1、str 开头的 函数 处理SBCS字符串&lt;br /&gt;2、wcs 开头的 函数 处理宽字符串，wcs是宽字符串的英文缩写&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 所有的unicode函数均以wcs开头。若要调用Unicode函数，只需用前缀wcs来取代ANSI字符串函数的前缀str即可。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 对于每一个标准的ANSI C字符串函数，基本都有等价的unicode函数.&lt;br /&gt;3、_mbs 开头的 函数 处理DBCS字符串&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 微软还在它的CRT(C runtime library)中增加了操作DBCS字符串的版本。Str***()函数都有对应名字的DBCS版本_mbs***()。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果你料到可能会遇到DBCS字符串（如果你的软件会被安装在使用DBCS编码的国家，如中国，日本等，你就可能会），你应该使用_mbs***()函数，因为他们也可以处理SBCS字符串。（一个DBCS字符串也可能含有单字节字符，这就是为什么_mbs***()函数也能处理SBCS字符串的原因）。微软还提供了几个函数方便对dbcs的处理 ， 见后面的描述。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果只是调用strlen函数，那么你无法真正了解字符串中究竟有多少字符，它只能告诉你到达结尾的0之前有多少个字节。ANSI的C运行期库中没有配备相应的函数，使你能够对双字节字符集进行操作。但是，Microsoft Visual C++的运行期库却包含许多函数，如_mbslen ,它可以用来操作多字节（既包括单字节也包括双字节）字符串。&lt;br /&gt;4、_tcs 开头的 宏 配合TCHAR使用&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 根据预定义分别扩展为str wcs _mbs， 见后面的描述。&lt;br /&gt;5、l开头的windows自带的宽字符处理函数&lt;br /&gt;6、大小写兼有的 windows自带的宽字符处理函数&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5和6见后面的描述&lt;br /&gt;更进一步的字符串以及其指针的类型定义&lt;/p&gt;&lt;p&gt;　由于Win32 API文档的函数列表使用函数的常用名字（例如， "SetWindowText"），所有的字符串都是用TCHAR来定义的。（除了XP中引入的只适用于Unicode的API）。下面列出一些常用的 typedefs，你可以在msdn中看到他们。&lt;br /&gt;type&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Meaning in MBCS builds&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; Meaning in Unicode builds&amp;nbsp;&lt;br /&gt;WCHAR&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; wchar_t&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;wchar_t&amp;nbsp;&lt;br /&gt;LPSTR&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; char*&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; char*&lt;br /&gt;LPCSTR&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; const char*&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const char*&lt;br /&gt;LPWSTR&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; wchar_t*&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;wchar_t*&amp;nbsp;&lt;br /&gt;LPCWSTR&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; const wchar_t*&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; const wchar_t*&amp;nbsp;&amp;nbsp;&lt;br /&gt;TCHAR&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; char&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;wchar_t&amp;nbsp;&lt;br /&gt;LPTSTR&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;TCHAR*&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TCHAR*&amp;nbsp;&lt;br /&gt;LPCTSTR&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; const TCHAR*&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; const TCHAR*&lt;/p&gt;&lt;p&gt;&lt;u&gt;4.strings(字符串)详解(一)&amp;nbsp;&lt;/u&gt;&lt;br /&gt;之所以抛弃char*的字符串而选用C++标准程序库中的string类，是因为他和前者比较起来，不必担心内存是否足够、字符串长度等等，而且作为一个类出现，他集成的操作函数足以完成我们大多数情况下(甚至是100%)的需要。我们可以用 = 进行赋值操作，== 进行比较，+ 做串联（是不是很简单?）。我们尽可以把它看成是C++的基本数据类型。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;好了，进入正题&amp;#8230;&amp;#8230;&amp;#8230;&lt;br /&gt;首先，为了在我们的程序中使用 string类型，我们必须包含头文件 &amp;lt;string&amp;gt;。如下：&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#include &amp;lt;string&amp;gt; //注意这里不是string.h string.h是C字符串头文件&lt;br /&gt;&lt;br /&gt;1．声明一个C++字符串&lt;br /&gt;声明一个字符串变量很简单：&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string Str;&lt;br /&gt;这样我们就声明了一个字符串变量，但既然是一个类，就有构造函数和析构函数。上面的声明没有传入参数，所以就直接使用了string的默认的构造函数，这个函数所作的就是把Str初始化为一个空字符串。String类的构造函数和析构函数如下：&lt;br /&gt;a)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string s;&amp;nbsp;&amp;nbsp;//生成一个空字符串s&lt;br /&gt;b)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string s(str) //拷贝构造函数 生成str的复制品&lt;br /&gt;c)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string s(str,stridx) //将字符串str内&amp;#8220;始于位置stridx&amp;#8221;的部分当作字符串的初值&lt;br /&gt;d)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string s(str,stridx,strlen) //将字符串str内&amp;#8220;始于stridx且长度顶多strlen&amp;#8221;的部分作为字符串的初值&lt;br /&gt;e)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string s(cstr) //将C字符串作为s的初值&lt;br /&gt;f)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string s(chars,chars_len) //将C字符串前chars_len个字符作为字符串s的初值。&lt;br /&gt;g)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string s(num,c) //生成一个字符串，包含num个c字符&lt;br /&gt;h)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string s(beg,end) //以区间beg;end(不包含end)内的字符作为字符串s的初值&lt;br /&gt;i)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.~string() //销毁所有字符，释放内存&lt;br /&gt;都很简单，我就不解释了。&lt;br /&gt;2．字符串操作函数&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;这里是C++字符串的重点，我先把各种操作函数罗列出来，不喜欢把所有函数都看完的人可以在这里找自己喜欢的函数，再到后面看他的详细解释。&lt;br /&gt;a) =,assign()&amp;nbsp;&amp;nbsp; //赋以新值&lt;br /&gt;b) swap()&amp;nbsp;&amp;nbsp; //交换两个字符串的内容&lt;br /&gt;c) +=,append(),push_back() //在尾部添加字符&lt;br /&gt;d) insert() //插入字符&lt;br /&gt;e) erase() //删除字符&lt;br /&gt;f) clear() //删除全部字符&amp;nbsp;&lt;br /&gt;g) replace() //替换字符&lt;br /&gt;h) + //串联字符串&lt;br /&gt;i) ==,!=,&amp;lt;,&amp;lt;=,&amp;gt;,&amp;gt;=,compare()&amp;nbsp;&amp;nbsp;//比较字符串&lt;br /&gt;j) size(),length()&amp;nbsp;&amp;nbsp;//返回字符数量&lt;br /&gt;k) max_size() //返回字符的可能最大个数&lt;br /&gt;l) empty()&amp;nbsp;&amp;nbsp;//判断字符串是否为空&lt;br /&gt;m) capacity() //返回重新分配之前的字符容量&lt;br /&gt;n) reserve() //保留一定量内存以容纳一定数量的字符&lt;br /&gt;o) [ ], at() //存取单一字符&lt;br /&gt;p) &amp;gt;&amp;gt;,getline() //从stream读取某值&lt;br /&gt;q) &amp;lt;&amp;lt;&amp;nbsp;&amp;nbsp;//将谋值写入stream&lt;br /&gt;r) copy() //将某值赋值为一个C_string&lt;br /&gt;s) c_str() //将内容以C_string返回&lt;br /&gt;t) da&lt;wbr&gt;ta() //将内容以字符数组形式返回&lt;br /&gt;u) substr() //返回某个子字符串&lt;br /&gt;v)查找函数&lt;br /&gt;w)begin() end() //提供类似STL的迭代器支持&lt;br /&gt;x) rbegin() rend() //逆向迭代器&lt;br /&gt;y) get_allocator() //返回配置器&lt;br /&gt;下面详细介绍：&lt;br /&gt;2．1 C++字符串和C字符串的转换&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;C++提供的由C++字符串得到对应的 C_string的方法是使用da&lt;wbr&gt;ta()、c_str()和copy()，其中，da&lt;wbr&gt;ta()以字符数组的形式返回字符串内容，但并不添加&amp;#8217;\0&amp;#8217;。 c_str()返回一个以&amp;#8216;\0&amp;#8217;结尾的字符数组，而copy()则把字符串的内容复制或写入既有的c_string或字符数组内。C++字符串并不以&amp;#8217; \0&amp;#8217;结尾。我的建议是在程序中能使用C++字符串就使用，除非万不得已不选用c_string。由于只是简单介绍，详细介绍掠过，谁想进一步了解使用中的注意事项可以给我留言(到我的收件箱)。我详细解释。&lt;br /&gt;2．2 大小和容量函数&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一个C++字符串存在三种大小：a)现有的字符数，函数是size()和length()，他们等效。Empty()用来检查字符串是否为空。b)max_size() 这个大小是指当前C++字符串最多能包含的字符数，很可能和机器本身的限制或者字符串所在位置连续内存的大小有关系。我们一般情况下不用关心他，应该大小足够我们用的。但是不够用的话，会抛出length_error异常c)capacity()重新分配内存之前 string所能包含的最大字符数。这里另一个需要指出的是reserve()函数，这个函数为string重新分配内存。重新分配的大小由其参数决定，默认参数为0，这时候会对string进行非强制性缩减。&lt;/p&gt;&lt;p&gt;还有必要再重复一下C++字符串和C字符串转换的问题，许多人会遇到这样的问题，自己做的程序要调用别人的函数、类什么的（比如数据库连接函数Connect(char*,char*)），但别人的函数参数用的是char*形式的，而我们知道，c_str()、da&lt;wbr&gt;ta()返回的字符数组由该字符串拥有，所以是一种const char*,要想作为上面提及的函数的参数，还必须拷贝到一个char*,而我们的原则是能不使用C字符串就不使用。那么，这时候我们的处理方式是：如果此函数对参数(也就是char*)的内容不修改的话，我们可以这样Connect((char*)UserID.c_str(), (char*)PassWD.c_str()),但是这时候是存在危险的，因为这样转换后的字符串其实是可以修改的（有兴趣地可以自己试一试），所以我强调除非函数调用的时候不对参数进行修改，否则必须拷贝到一个char*上去。当然，更稳妥的办法是无论什么情况都拷贝到一个char*上去。同时我们也祈祷现在仍然使用C字符串进行编程的高手们（说他们是高手一点儿也不为过，也许在我们还穿开裆裤的时候他们就开始编程了，哈哈&amp;#8230;）写的函数都比较规范，那样我们就不必进行强制转换了。&lt;br /&gt;&lt;br /&gt;2．3元素存取&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;我们可以使用下标操作符[]和函数at()对元素包含的字符进行访问。但是应该注意的是操作符[]并不检查索引是否有效（有效索引0~str.length()），如果索引失效，会引起未定义的行为。而at()会检查，如果使用 at()的时候索引无效，会抛出out_of_range异常。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;有一个例外不得不说，const string a;的操作符[]对索引值是a.length()仍然有效，其返回值是&amp;#8217;\0&amp;#8217;。其他的各种情况，a.length()索引都是无效的。举例如下：&lt;br /&gt;const string Cstr(&amp;#8220;const string&amp;#8221;);&lt;br /&gt;string Str(&amp;#8220;string&amp;#8221;);&lt;br /&gt;&lt;br /&gt;Str[3];&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//ok&lt;br /&gt;Str.at(3);&amp;nbsp;&amp;nbsp;//ok&lt;br /&gt;&lt;br /&gt;Str[100]; //未定义的行为&lt;br /&gt;Str.at(100);&amp;nbsp;&amp;nbsp;//throw out_of_range&lt;br /&gt;&lt;br /&gt;Str[Str.length()]&amp;nbsp;&amp;nbsp;// 未定义行为&lt;br /&gt;Cstr[Cstr.length()] //返回 &amp;#8216;\0&amp;#8217;&lt;br /&gt;Str.at(Str.length());//throw out_of_range&lt;br /&gt;Cstr.at(Cstr.length()) ////throw out_of_range&lt;br /&gt;&lt;br /&gt;我不赞成类似于下面的引用或指针赋值：&lt;br /&gt;char&amp;amp; r=s[2];&lt;br /&gt;char* p= &amp;amp;s[3];&lt;br /&gt;因为一旦发生重新分配，r,p立即失效。避免的方法就是不使用。&lt;br /&gt;&lt;br /&gt;2．4比较函数&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;C++字符串支持常见的比较操作符（&amp;gt;,&amp;gt;=,&amp;lt;,&amp;lt;=,==,!=），甚至支持string与C-string的比较(如 str&amp;lt;&amp;#8221;hello&amp;#8221;)。在使用&amp;gt;,&amp;gt;=,&amp;lt;,&amp;lt;=这些操作符的时候是根据&amp;#8220;当前字符特性&amp;#8221;将字符按字典顺序进行逐一得比较。字典排序靠前的字符小，比较的顺序是从前向后比较，遇到不相等的字符就按这个位置上的两个字符的比较结果确定两个字符串的大小。同时，string(&amp;#8220;aaaa&amp;#8221;) &amp;lt;string(aaaaa)。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;另一个功能强大的比较函数是成员函数compare()。他支持多参数处理，支持用索引值和长度定位子串来进行比较。他返回一个整数来表示比较结果，返回值意义如下：0-相等 〉0-大于 &amp;lt;0-小于。举例如下：&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string s(&amp;#8220;abcd&amp;#8221;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.compare(&amp;#8220;abcd&amp;#8221;); //返回0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.compare(&amp;#8220;dcba&amp;#8221;); //返回一个小于0的值&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.compare(&amp;#8220;ab&amp;#8221;); //返回大于0的值&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;s.compare(s); //相等&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.compare(0,2,s,2,2); //用&amp;#8221;ab&amp;#8221;和&amp;#8221;cd&amp;#8221;进行比较 小于零&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.compare(1,2,&amp;#8221;bcx&amp;#8221;,2); //用&amp;#8221;bc&amp;#8221;和&amp;#8221;bc&amp;#8221;比较。&lt;br /&gt;怎么样？功能够全的吧！什么？还不能满足你的胃口？好吧，那等着，后面有更个性化的比较算法。先给个提示，使用的是STL的比较算法。什么？对STL一窍不通？靠，你重修吧！&lt;br /&gt;&lt;br /&gt;2．5 更改内容&lt;br /&gt;这在字符串的操作中占了很大一部分。&lt;br /&gt;首先讲赋值，第一个赋值方法当然是使用操作符=，新值可以是string(如：s=ns) 、c_string(如：s=&amp;#8221;gaint&amp;#8221;)甚至单一字符（如：s=&amp;#8217;j&amp;#8217;）。还可以使用成员函数assign()，这个成员函数可以使你更灵活的对字符串赋值。还是举例说明吧：&lt;br /&gt;s.assign(str); //不说&lt;br /&gt;s.assign(str,1,3);//如果str 是&amp;#8221;iamangel&amp;#8221; 就是把&amp;#8221;ama&amp;#8221;赋给字符串&lt;br /&gt;s.assign(str,2,string::npos);//把字符串str从索引值2 开始到结尾赋给s&lt;br /&gt;s.assign(&amp;#8220;gaint&amp;#8221;); //不说&lt;br /&gt;s.assign(&amp;#8220;nico&amp;#8221;,5);//把&amp;#8217;n&amp;#8217; &amp;#8216;I&amp;#8217; &amp;#8216;c&amp;#8217; &amp;#8216;o&amp;#8217; &amp;#8216;\0&amp;#8217;赋给字符串&lt;br /&gt;s.assign(5,&amp;#8217;x&amp;#8217;);//把五个x赋给字符串&lt;br /&gt;把字符串清空的方法有三个：s=&amp;#8221;&amp;#8221;; s.clear();s.erase();(我越来越觉得举例比说话让别人容易懂！)。&lt;br /&gt;string提供了很多函数用于插入（insert）、删除（erase）、替换（replace）、增加字符。&lt;br /&gt;先说增加字符（这里说的增加是在尾巴上），函数有 +=、append()、push_back()。举例如下：&lt;br /&gt;s+=str;//加个字符串&lt;br /&gt;s+=&amp;#8221;my name is jiayp&amp;#8221;;//加个C字符串&lt;br /&gt;s+=&amp;#8217;a&amp;#8217;;//加个字符&lt;br /&gt;&lt;br /&gt;s.append(str);&lt;br /&gt;s.append(str,1,3);// 不解释了 同前面的函数参数assign的解释&lt;br /&gt;s.append(str,2,string::npos)//不解释了&lt;br /&gt;&lt;br /&gt;s.append(&amp;#8220;my name is jiayp&amp;#8221;);&lt;br /&gt;s.append(&amp;#8220;nico&amp;#8221;,5);&lt;br /&gt;s.append(5,&amp;#8217;x&amp;#8217;);&lt;br /&gt;&lt;br /&gt;s.push_back(&amp;#8216;a&amp;#8217;);// 这个函数只能增加单个字符 对STL熟悉的理解起来很简单&lt;br /&gt;&lt;br /&gt;也许你需要在string中间的某个位置插入字符串，这时候你可以用 insert()函数，这个函数需要你指定一个安插位置的索引，被插入的字符串将放在这个索引的后面。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.insert(0,&amp;#8221;my name&amp;#8221;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s.insert(1,str);&lt;br /&gt;这种形式的insert()函数不支持传入单个字符，这时的单个字符必须写成字符串形式(让人恶心)。既然你觉得恶心，那就不得不继续读下面一段话：为了插入单个字符，insert()函数提供了两个对插入单个字符操作的重载函数：insert(size_type index,size_type num,chart c)和insert(iterator pos,size_type num,chart c)。其中size_type是无符号整数，iterator是char*,所以，你这么调用insert函数是不行的：insert(0,1,&amp;#8217;j&amp;#8217;);这时候第一个参数将转换成哪一个呢？所以你必须这么写：insert((string::size_type)0,1,&amp;#8217;j&amp;#8217;)！第二种形式指出了使用迭代器安插字符的形式，在后面会提及。顺便提一下，string有很多操作是使用STL的迭代器的，他也尽量做得和STL靠近。&lt;br /&gt;删除函数erase()的形式也有好几种（真烦！），替换函数 replace()也有好几个。举例吧：&lt;br /&gt;string s=&amp;#8221;il8n&amp;#8221;;&lt;br /&gt;s.replace(1,2,&amp;#8221;nternationalizatio&amp;#8221;);// 从索引1开始的2个替换成后面的C_string&lt;br /&gt;s.erase(13);//从索引13开始往后全删除&lt;br /&gt;s.erase(7,5);// 从索引7开始往后删5个&lt;br /&gt;&lt;br /&gt;2．6提取子串和字符串连接&lt;br /&gt;&lt;br /&gt;题取子串的函数是：substr(),形式如下：&lt;br /&gt;s.substr();// 返回s的全部内容&lt;br /&gt;s.substr(11);//从索引11往后的子串&lt;br /&gt;s.substr(5,6);//从索引5开始6个字符&lt;br /&gt;把两个字符串结合起来的函数是+。（谁不明白请致电120）&lt;br /&gt;&lt;br /&gt;2．7输入输出操作&lt;br /&gt;1．&amp;gt;&amp;gt; 从输入流读取一个string。&lt;br /&gt;2．&amp;lt;&amp;lt; 把一个string写入输出流。&lt;br /&gt;另一个函数就是getline(),他从输入流读取一行内容，直到遇到分行符或到了文件尾。&lt;br /&gt;&lt;br /&gt;2．8搜索与查找&lt;br /&gt;查找函数很多，功能也很强大，包括了：&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;find()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rfind()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;find_first_of()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;find_last_of()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;find_first_not_of()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;find_last_not_of()&lt;br /&gt;这些函数返回符合搜索条件的字符区间内的第一个字符的索引，没找到目标就返回npos。所有的函数的参数说明如下：&lt;br /&gt;第一个参数是被搜寻的对象。第二个参数（可有可无）指出string内的搜寻起点索引，第三个参数（可有可无）指出搜寻的字符个数。比较简单，不多说 不理解的可以向我提出，我再仔细的解答。当然，更加强大的STL搜寻在后面会有提及。&lt;br /&gt;最后再说说npos的含义，string::npos的类型是string::size_type,所以，一旦需要把一个索引与npos相比，这个索引值必须是string::size)type类型的，更多的情况下，我们可以直接把函数和npos进行比较（如：if(s.find(&amp;#8220;jia&amp;#8221;)==string::npos)）。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;第二部分是关于 C++字符串对迭代器的支持的，视大家的需要我将写出来（意思就是不需要就算了，我乐得轻省，哈哈&amp;#8230;）。&lt;br /&gt;好了，大概的对string类型进行了阐述，希望起到抛砖引玉的作用，让初学者对string有个了解而不必已开始就面对复杂的内部结构和无数个注意事项。对字符串更详细地讲解有很多参考书，其实我的内容也是从C++标准程序库得来的，加上几句自己的看法，所以要感谢这本书的作者和译者。任何人对本文进行引用都要标明作者是Nicolai M.Josuttis 译者是侯捷/孟岩。不过不要提及我，任何观点的错误都与我无关（除了这里边体现我主观想法的几句话，也就那几句话）。&lt;/p&gt;&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/SweetDream/aggbug/1915667.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/SweetDream/archive/2010/12/24/1915667.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/SweetDream/archive/2010/12/13/1904224.html</id><title type="text">【转】Linux内核学习笔记（5）连载---实模式、保护模式和虚拟8086方式</title><summary type="text">从80386开始，cpu有三种工作方式：实模式，保护模式和虚拟8086模式。只有在刚刚启动的时候是real-mode，等到linux操作系统运行起来以后就运行在保护模式。实模式只能访问地址在1M以下的内存称为常规内存，我们把地址在1M 以上的内存称为扩展内存。在保护模式下，全部32条地址线有效，可寻址高达4G字节的物理地址空间; 扩充的存储器分段管理机制和可选的存储器分页管理机制，不仅为存储器共享和保护提供了硬件支持，而且为实现虚拟存储器提供了硬件支持; 支持多任务，能够快速地进行任务切换和保护任务环境; 4个特权级和完善的特权检查机制，既能实现资源共享又能保证代码和数据的安全和保密及任务的隔</summary><published>2010-12-13T03:09:00Z</published><updated>2010-12-13T03:09:00Z</updated><author><name>SweetDream</name><uri>http://www.cnblogs.com/SweetDream/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SweetDream/archive/2010/12/13/1904224.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SweetDream/archive/2010/12/13/1904224.html"/><content type="html">&lt;div&gt;&lt;span style="font-family: Arial; line-height: 18px; font-size: 12px; color: #666666; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; "&gt;&lt;p&gt;从80386开始，cpu有三种工作方式：实模式，保护模式和虚拟8086模式。只有在刚刚启动的时候是real-mode，等到linux操作系统运行起来以后就运行在保护模式。实模式只能访问地址在1M以下的内存称为常规内存，我们把地址在1M 以上的内存称为扩展内存。在保护模式下，全部32条地址线有效，可寻址高达4G字节的物理地址空间; 扩充的存储器分段管理机制和可选的存储器分页管理机制，不仅为存储器共享和保护提供了硬件支持，而且为实现虚拟存储器提供了硬件支持; 支持多任务，能够快速地进行任务切换和保护任务环境; 4个特权级和完善的特权检查机制，既能实现资源共享又能保证代码和数据的安全和保密及任务的隔离; 支持虚拟8086方式，便于执行8086程序。&lt;img src="http://img.baidu.com/hi/tsj/t_0009.gif" style="line-height: normal; "  alt="" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 虚拟8086模式是运行在保护模式中的实模式，为了在32位保护模式下执行纯16位程序。它不是一个真正的CPU模式，还属于保护模式。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 保护模式同实模式的根本区别是进程内存受保护与否。可寻址空间的区别只是这一原因的果。实模式将整个物理内存看成分段的区域,程序代码和数据位于不同区域，系统程序和用户程序没有区别对待，而且每一个指针都是指向"实在"的物理地址。这样一来，用户程序的一个指针如果指向了系统程序区域或其他用户程序区域，并改变了值，那么对于这个被修改的系统程序或用户程序，其后果就很可能是灾难性的。为了克服这种低劣的内存管理方式，处理器厂商开发出保护模式。这样，物理内存地址不能直接被程序访问，程序内部的地址（虚拟地址）要由操作系统转化为物理地址去访问，程序对此一无所知。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 至此，进程（这时我们可以称程序为进程了）有了严格的边界，任何其他进程根本没有办法访问不属于自己的物理内存区域，甚至在自己的虚拟地址范围内也不是可以任意访问的，因为有一些虚拟区域已经被放进一些公共系统运行库。这些区域也不能随便修改，若修改就会有: SIGSEGV（linux 段错误）;非法内存访问对话框（windows 对话框）。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CPU启动环境为16位实模式，之后可以切换到保护模式。但从保护模式无法切换回实模式 !!&lt;/p&gt;&lt;p&gt;事实上，现在的64位奔腾4处理器，拥有三种基本模式和一种扩展模式，&amp;nbsp;&lt;br style="line-height: normal; " /&gt;基本模式：&amp;nbsp;&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 保护模式：纯32位保护执行环境。&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 实模式：纯16位无保护执行环境。&amp;nbsp;&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 系统管理模式：当SMI引脚为有效进入系统管理模式，首先保存当前的CPU上下文。它有独立的地址空间，用来执行电源管理或系统安全方面的指令。&amp;nbsp;&lt;br style="line-height: normal; " /&gt;扩展模式：&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; IA-32e模式: 64位操作系统运行在该模式。该模式有两种子模式:&amp;nbsp;&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1）兼容模式：该模式下，64位操作系统运行在32位兼容环境，能正常运行16，32位应用程序就像基本的保护模式一样， 访问32位地址空间，但不能运行纯16位实模式程序（就是不能运行虚拟86模式程序了）。&amp;nbsp;&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2）64位模式：在该模式下，处理器完全执行64位指令，使用64位地址空间和64操作数，运行16，32位程序必须切换到兼容模式。&lt;br style="line-height: normal; " /&gt;IA-32e子模式的切换完全基于代码段寄存器。这样一来，运行在IA-32e模式中（64位）的OS完全可以无缝的运行所有16，32，64为应用程序， 通过设置32位后的CS。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;br style="line-height: normal; " /&gt;1:实模式：寻址采用和8086相同的16位段和偏移量，最大寻址空间1MB，最大分段64KB。可以使用32位指令。32位的x86 CPU用做高速的8086。&lt;br style="line-height: normal; " /&gt;2:保护模式：寻址采用32位段和偏移量，最大寻址空间4GB，最大分段4GB (Pentium Pre及以后为64GB)。在保护模式下CPU可以进入虚拟8086方式，这是在保护模式下的实模式程序运行环境。&lt;/p&gt;&lt;p&gt;第一:实模式下程序的运行回顾.&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 程序运行的实质是什么?其实很简单,就是指令的执行,显然CPU是指令得以执行的硬件保障,那么CPU如何知道指令在什么地方呢?对了,80x86系列是使用CS寄存器配合IP寄存器来通知CPU指令在内存中的位置.&amp;nbsp;&amp;nbsp; 程序指令在执行过程中一般还需要有各种数据,80x86系列有DS、ES、FS、GS、SS等用于指示不同用途的数据段在内存中的位置。&amp;nbsp;&amp;nbsp; 程序可能需要调用系统的服务子程序，80x86系列使用中断机制来实现系统服务。&amp;nbsp;&amp;nbsp; 总的来说，这些就是实模式下一个程序运行所需的主要内容（其它如跳转、返回、端口操作等相对来说比较次要。）&lt;/p&gt;&lt;p&gt;第二：保护模式---从程序运行说起&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 无论实模式还是保护模式，根本的问题还是程序如何在其中运行。因此我们在学习保护模式时应该时刻围绕这个问题来思考。&amp;nbsp;&amp;nbsp; 和实模式下一样，保护模式下程序运行的实质仍是&amp;#8220;CPU执行指令，操作相关数据&amp;#8221;，因此实模式下的各种代码段、数据段、堆栈段、中断服务程序仍然存在，且功能、作用不变。&amp;nbsp;&amp;nbsp; 那么保护模式下最大的变化是什么呢？答案可能因人而异，我的答案是&amp;#8220;地址转换方式&amp;#8221;变化最大。&lt;br style="line-height: normal; " /&gt;第三：地址转换方式比较&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 先看一下实模式下的地址转换方式，假设我们在ES中存入0x1000，DI中存入0xFFFF,那么ES:DI=0x1000*0x10+0xFFFF=0x1FFFF,这就是众所周知的&amp;#8220;左移4位加偏移&amp;#8221;。&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;那么如果在保护模式下呢？假设上面的数据不变ES=0x1000,DI=0xFFFF，现在ES:DI等于什么呢？&amp;nbsp;&amp;nbsp; 公式如下：（注：0x1000=1000000000000b= 10 0000 0000 0 00）&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;ES:DI=全局描述符表中第0x200项描述符给出的段基址+0xFFFF&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;现在比较一下，好象是不一样。再仔细看看，又好象没什么区别！&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 为什么说没什么区别，因为我的想法是，既然ES中的内容都不是真正的段地址，凭什么实模式下称ES为&amp;#8220;段寄存器&amp;#8221;，而到了保护模式就说是&amp;#8220;选择子&amp;#8221;？&amp;nbsp;&amp;nbsp; 其实它们都是一种映射，只是映射规则不同而已：在实模式下这个&amp;#8220;地址转换方式&amp;#8221;是&amp;#8220;左移4位&amp;#8221;；在保护模式下是&amp;#8220;查全局/局部描述表&amp;#8221;。前者是系统定义的映射方式，后者是用户自定义的转换方式。而它影响的都是&amp;#8220;shadow register&amp;#8221; 从函数的观点来看，前者是表达式函数，后者是列举式函数：&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 实模式： F(es--&amp;gt;segment)={segment |segment=es*0x10}&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 保护模式：F(es--&amp;gt;segment)={segment |(es,segment)&amp;#8712;GDT/LDT}&lt;br style="line-height: normal; " /&gt;其中GDT、LDT分别表示全局描述符表和局部描述符表。&lt;/p&gt;&lt;p&gt;第四：保护模式基本组成&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 保护模式最基本的组成部分是围绕着&amp;#8220;地址转换方式&amp;#8221;的变化增设了相应的机构。&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 1、数据段&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 前面说过，实模式下的各种代码段、数据段、堆栈段、中断服务程序仍然存在，我将它们统称为&amp;#8220;数据段&amp;#8221;，本文从此向下凡提到数据段都是使用这个定义。&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 2、描述符&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 保护模式下引入描述符来描述各种数据段，所有的描述符均为8个字节（0-7)，由第5个字节说明描述符的类型，类型不同，描述符的结构也有所不同。&amp;nbsp;&amp;nbsp; 若干个描述符集中在一起组成描述符表，而描述符表本身也是一种数据段，也使用描述符进行描述。&amp;nbsp;&amp;nbsp; 从现在起，&amp;#8220;地址转换&amp;#8221;由描述符表来完成，从这个意义上说，描述符表是一张地址转换函数表。&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 3、选择子&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 选择子是一个2字节的数，共16位，最低2位表示RPL，第3位表示查表是利用GDT（全局描述符表）还是LDT（局部描述符表）进行，最高13位给出了所需的描述符在描述符表中的地址。（注：13位正好足够寻址8K项）&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp; 有了以上三个概念之后可以进一步工作了，现在程序的运行与实模式下完全一样！！！各段寄存器仍然给出一个&amp;#8220;段值&amp;#8221;，只是这个&amp;#8220;假段值&amp;#8221;到真正的段地址的转换不再是&amp;#8220;左移4位&amp;#8221;，而是利用描述符表来完成。但现在出现一个新的问题是：&amp;nbsp;&amp;nbsp; 系统如何知道GDT/LDT在内存中的位置呢？&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 为了解决这个问题，显然需要引入新的寄存器用于指示GDT/LDT在内存中的位置。在80x86系列中引入了两个新寄存器GDR和LDR，其中GDR用于表示GDT在内存中的段地址和段限（就是表的大小），因此GDR是一个48位的寄存器，其中32位表示段地址，16位表示段限（最大64K，每个描述符8字节，故最多有64K/8=8K个描述符）。LDR用于表示LDT在内存中的位置，但是因为LDT本身也是一种数据段，它必须有一个描述符，且该描述符必须放在GDT中，因此LDR使用了与DS、ES、CS等相同的机制，其中只存放一个&amp;#8220;选择子&amp;#8221;，通过查GDT表获得LDT的真正内存地址。&amp;nbsp;&amp;nbsp; 对了，还有中断要考虑，在80x86系列中为中断服务提供中断/陷阱描述符，这些描述符构成中断描述符表（IDT），并引入一个48位的全地址寄存器存放IDT的内存地址。理论上IDT表同样可以有8K项，可是因为80x86只支持256个中断，因此IDT实际上最大只能有256项（2K大小）。&lt;/p&gt;&lt;p&gt;第五：新要求---任务篇&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 前面介绍了保护模式的基本问题，也是核心问题，解决了上面的问题，程序就可以在保护模式下运行了。&amp;nbsp;&amp;nbsp; 但众所周知80286以后在保护模式下实现了对多任务的硬件支持。我的第一反应是：为什么不在实模式下支持多任务，是不能还是不愿？&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 思考之后，我的答案是：实模式下能实现多任务（也许我错了：））。因为多任务的关键是有了描述符，可以给出关于数据段的额外描述，如权限等，进而在这些附加信息的基础上进行相应的控制，而实模式下缺乏描述符，但假设我们规定各段的前2个字节或若干字节用于描述段的附加属性，我觉得和使用描述符这样的机制没有本质区别，如果再附加其他机制...&amp;nbsp;&amp;nbsp; 基于上述考虑，我更倾向于认为任务是独立于保护模式之外的功能。下面我们来分析一下任务。任务的实质是什么呢？很简单，就是程序嘛！！所谓任务的切换其实就是程序的切换！！&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 现在问题明朗了。实模式下程序一个接一个运行，因此程序运行的&amp;#8220;环境&amp;#8221;不必保存；保护模式下可能一个程序在运行过程中被暂停，转而执行下一个程序，我们要做什么？很容易想到保存程序运行的环境就行了（想想游戏程序的保存进度功能），比如各寄存器的值等。&amp;nbsp;&amp;nbsp; 显然这些&amp;#8220;环境&amp;#8221;数据构成了一类新的数据段（即TSS）。延用前面的思路，给这类数据段设置描述符（TSS描述符），将该类描述符放在GDT中（不能放在LDT中，因为80x86不允许：）），最后再加一个TR寄存器用于查表。TR是一个起&amp;#8220;选择子&amp;#8221;作用的寄存器，16位。&amp;nbsp;&amp;nbsp; 好了，任务切换的基本工作就是将原任务的&amp;#8220;环境&amp;#8221;存入TSS数据段，更新TR寄存器，系统将自动查GDT表获得并装载新任务的&amp;#8220;环境&amp;#8221;，然后转到新任务执行。&lt;/p&gt;&lt;p&gt;第六：附加要求---分页篇&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 为什么叫附加要求，因为现在任务还不能很好地工作。前面说过，任务实质上是程序，不同的程序是由不同的用户写的，所有这些程序完全可能使用相同的地址空间，而任务的切换过程一般不会包括内存数据的刷新，不是不可能，而是如果那样做太浪费了。因此必须引入分页机制才可能有效地完成对多任务的支持。&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 分页引入的主要目标就是解决不同任务相互之间发生地址冲突的问题。分页的实质就是实现程序内地址到物理地址的映射，这也是一个&amp;#8220;地址转换&amp;#8221;机制，同样可以使用前面的方案（即类似GDT的做法）：首先建立页表这样一种数据段，在80x86中使用二级页表方案，增设一个CR3寄存器用于存放一级页表（又称为页目录）在内存中的地址，CR3共32位，其低12位总是为零，高20位指示页目录的内存地址，因此页目录总是按页对齐的。CR3作为任务&amp;#8220;环境&amp;#8221;的一部分在任务切换时被存入TSS数据段中。&amp;nbsp;&amp;nbsp; 当然还得有相应的缺页中断机制及其相关寄存器CR2（页故障线性地址寄存器）。&lt;/p&gt;&lt;p&gt;第七：总结&amp;nbsp;&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 保护模式下增加了什么？&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 1、寄存器 GDR LDR IDR TR CR3&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 2、数据段 描述符表(GDT LDT) 任务数据段(TSS) 页表(页目录 二级页表)&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 3、机制&amp;nbsp;&amp;nbsp; 权限检测(利用选择子/描述符/页表项的属性位)&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 线性地址到物理地址的映射&lt;/p&gt;&lt;p&gt;第八：保护模式常用名词解释&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 前面内容中出现过的不再解释。&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 1、RPL 选择子当中的权限位确定的权限&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 2、CPL 特指CS中的选择子当中的权限位确定的权限&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 3、EPL EPL=Max(RPL,CPL),即RPL和CPL中数值较大的，或说权限等级较小的&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 4、DPL 描述符中的权限位确定的权限&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 5、PL&amp;nbsp;&amp;nbsp; 泛指以上4种特权级&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 6、任务特权&amp;nbsp;&amp;nbsp;&amp;nbsp; =CPL&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 7、I/O特权&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 由EFLAGS寄存器的位13、14确定的权限&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp; 8、一致代码段 一种特殊的代码段，它在CPL&amp;gt;=DPL时允许访问&lt;br style="line-height: normal; " /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 正常的代码段在CPL=DPL RPL&amp;lt;=DPL时才允许访问&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/SweetDream/aggbug/1904224.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/SweetDream/archive/2010/12/13/1904224.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/SweetDream/archive/2009/08/18/1549367.html</id><title type="text">concept</title><summary type="text">1.dbghelp 《天骄III》采用 Win32 平台上较为成熟的“最小化转储+崩溃后调试”的方案来解决可能遇到的各种程序错误问题：使用 dbghelp 库将程序在崩溃点的状态“冻结”到文件中，然后提交到研发部门恢复崩溃现场并进行错误分析。这种方法可以在不向最终用户发布任何调试信息（以免被人轻易地执行反向工程）的情况下最精确地重现错误、减少解决问...</summary><published>2009-08-18T14:21:00Z</published><updated>2009-08-18T14:21:00Z</updated><author><name>SweetDream</name><uri>http://www.cnblogs.com/SweetDream/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SweetDream/archive/2009/08/18/1549367.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SweetDream/archive/2009/08/18/1549367.html"/><content type="text">1.dbghelp 《天骄III》采用 Win32 平台上较为成熟的“最小化转储+崩溃后调试”的方案来解决可能遇到的各种程序错误问题：使用 dbghelp 库将程序在崩溃点的状态“冻结”到文件中，然后提交到研发部门恢复崩溃现场并进行错误分析。这种方法可以在不向最终用户发布任何调试信息（以免被人轻易地执行反向工程）的情况下最精确地重现错误、减少解决问...</content></entry><entry><id>http://www.cnblogs.com/SweetDream/archive/2009/03/28/1424149.html</id><title type="text">计算机英语</title><summary type="text">override       重写，子类重写基类；overload重载</summary><published>2009-03-28T14:21:00Z</published><updated>2009-03-28T14:21:00Z</updated><author><name>SweetDream</name><uri>http://www.cnblogs.com/SweetDream/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SweetDream/archive/2009/03/28/1424149.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SweetDream/archive/2009/03/28/1424149.html"/><content type="text">override       重写，子类重写基类；overload重载</content></entry><entry><id>http://www.cnblogs.com/SweetDream/archive/2009/03/11/1409058.html</id><title type="text">C++备忘录(记录一些不常使用的语法规则)</title><summary type="text">1.类成员函数的回调class MyClass{public:typedef void (MyClass::*CallBack)(int nParam1, int nParam2);void TestCallBack(int nParam1, int nParam2){return;}};void main(){MyClass::CallBack pfCallBack = &amp;...</summary><published>2009-03-11T12:24:00Z</published><updated>2009-03-11T12:24:00Z</updated><author><name>SweetDream</name><uri>http://www.cnblogs.com/SweetDream/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SweetDream/archive/2009/03/11/1409058.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SweetDream/archive/2009/03/11/1409058.html"/><content type="text">1.类成员函数的回调class MyClass{public:typedef void (MyClass::*CallBack)(int nParam1, int nParam2);void TestCallBack(int nParam1, int nParam2){return;}};void main(){MyClass::CallBack pfCallBack = &amp;...</content></entry><entry><id>http://www.cnblogs.com/SweetDream/archive/2008/12/02/1345733.html</id><title type="text">Effective STL 笔记 &lt;容器&gt;</title><summary type="text"> 1.容器无关代码不存在,也就是不存在一种万能的容器,任何容器都有它存在的价值和用武之地. 2.因为容器类型可能会改变所以不要这么写:class Widget {...};vector&lt;Widget&gt; vw;// ...Widget bestWidget;vector&lt;Widget&gt;::iteratori = find(vw.begin(), vw.end(), b...</summary><published>2008-12-02T05:47:00Z</published><updated>2008-12-02T05:47:00Z</updated><author><name>SweetDream</name><uri>http://www.cnblogs.com/SweetDream/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SweetDream/archive/2008/12/02/1345733.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SweetDream/archive/2008/12/02/1345733.html"/><content type="text"> 1.容器无关代码不存在,也就是不存在一种万能的容器,任何容器都有它存在的价值和用武之地. 2.因为容器类型可能会改变所以不要这么写:class Widget {...};vector&lt;Widget&gt; vw;// ...Widget bestWidget;vector&lt;Widget&gt;::iteratori = find(vw.begin(), vw.end(), b...</content></entry><entry><id>http://www.cnblogs.com/SweetDream/archive/2008/11/27/1342369.html</id><title type="text">VS2005 快捷键</title><summary type="text">CTRL + SHIFT + B生成解决方案CTRL + F7 生成编译CTRL + O 打开文件CTRL + SHIFT + O打开项目CTRL + SHIFT + C显示类视图窗口F4 显示属性窗口SHIFT + F4显示项目属性窗口CTRL + SHIFT + E显示资源视图F12 转到定义CTRL + F12转到声明CTRL + ALT + J对象浏览CTRL + ALT + F1帮助目录...</summary><published>2008-11-27T08:17:00Z</published><updated>2008-11-27T08:17:00Z</updated><author><name>SweetDream</name><uri>http://www.cnblogs.com/SweetDream/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SweetDream/archive/2008/11/27/1342369.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SweetDream/archive/2008/11/27/1342369.html"/><content type="text">CTRL + SHIFT + B生成解决方案CTRL + F7 生成编译CTRL + O 打开文件CTRL + SHIFT + O打开项目CTRL + SHIFT + C显示类视图窗口F4 显示属性窗口SHIFT + F4显示项目属性窗口CTRL + SHIFT + E显示资源视图F12 转到定义CTRL + F12转到声明CTRL + ALT + J对象浏览CTRL + ALT + F1帮助目录...</content></entry><entry><id>http://www.cnblogs.com/SweetDream/archive/2008/11/23/1339388.html</id><title type="text">网摘</title><summary type="text">[wow]api list: http://www.wowprogramming.com/docs/api[net work] light-weight network libraryhttp://vast.sourceforge.net/</summary><published>2008-11-23T06:20:00Z</published><updated>2008-11-23T06:20:00Z</updated><author><name>SweetDream</name><uri>http://www.cnblogs.com/SweetDream/</uri></author><link rel="alternate" href="http://www.cnblogs.com/SweetDream/archive/2008/11/23/1339388.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/SweetDream/archive/2008/11/23/1339388.html"/><content type="text">[wow]api list: http://www.wowprogramming.com/docs/api[net work] light-weight network libraryhttp://vast.sourceforge.net/</content></entry></feed>
