﻿<?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++博客-创新无极限</title><link>http://www.cppblog.com/sgq116300/</link><description>Sun Guoqing的Blog</description><language>zh-cn</language><lastBuildDate>Mon, 13 Apr 2026 09:42:01 GMT</lastBuildDate><pubDate>Mon, 13 Apr 2026 09:42:01 GMT</pubDate><ttl>60</ttl><item><title>WINCE的内存配置-config.bib文件的解析</title><link>http://www.cppblog.com/sgq116300/archive/2007/11/14/36577.html</link><dc:creator>sunGuoqin</dc:creator><author>sunGuoqin</author><pubDate>Wed, 14 Nov 2007 04:39:00 GMT</pubDate><guid>http://www.cppblog.com/sgq116300/archive/2007/11/14/36577.html</guid><wfw:comment>http://www.cppblog.com/sgq116300/comments/36577.html</wfw:comment><comments>http://www.cppblog.com/sgq116300/archive/2007/11/14/36577.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sgq116300/comments/commentRss/36577.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sgq116300/services/trackbacks/36577.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 关于WinCE的内存的分配。&nbsp;&nbsp;<a href='http://www.cppblog.com/sgq116300/archive/2007/11/14/36577.html'>阅读全文</a><img src ="http://www.cppblog.com/sgq116300/aggbug/36577.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sgq116300/" target="_blank">sunGuoqin</a> 2007-11-14 12:39 <a href="http://www.cppblog.com/sgq116300/archive/2007/11/14/36577.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于sizeof()的简单解析  </title><link>http://www.cppblog.com/sgq116300/archive/2007/11/14/36576.html</link><dc:creator>sunGuoqin</dc:creator><author>sunGuoqin</author><pubDate>Wed, 14 Nov 2007 04:35:00 GMT</pubDate><guid>http://www.cppblog.com/sgq116300/archive/2007/11/14/36576.html</guid><wfw:comment>http://www.cppblog.com/sgq116300/comments/36576.html</wfw:comment><comments>http://www.cppblog.com/sgq116300/archive/2007/11/14/36576.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cppblog.com/sgq116300/comments/commentRss/36576.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sgq116300/services/trackbacks/36576.html</trackback:ping><description><![CDATA[<p>在所有说明之前，给大家出一道题目：</p>
<p style="font-weight: bold;">int a=256;</p>
<p style="font-weight: bold;">printf("%d\n", sizeof(++a));</p>
<p style="font-weight: bold;">printf("%d\n", a);</p>
<p>那么到底打印的是多少呢？</p>
<p>应该是4和256，我想第一个答案大家应该已经没有问题了，但是为什么在++a以后，a的数值还是没有发生变化呢？因为sizeof（）是一个运算符，在其中的所有的运算都是无效的，所以++a根本就没有运行。</p>
<p>上面的一个例子提醒我们，虽然sizeof看这简单，但是其中还是有很多的问题值得讨论的，呵呵。<br></p>
<p><strong>一、sizeof的概念</strong>　&nbsp;<br>　　sizeof是C语言的一种单目操作符，如C语言的其他操作符++、--等。它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。<span class="Title">操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。　&nbsp;<br><br><strong>二、sizeof的使用方法　</strong>&nbsp;<br>　　<strong>1、用于数据类型　</strong>&nbsp;<br><br>　　sizeof使用形式：sizeof（type）　&nbsp;<br><br>　　数据类型必须用括号括住。如sizeof（int）。　&nbsp;<br><br>　　<strong>2、用于变量　</strong>&nbsp;<br><br>　　sizeof使用形式：sizeof（var_name）或sizeof　var_name　&nbsp;<br><br>　　变量名可以不用括号括住。如sizeof　(var_name)，sizeof　var_name等都是正确形式。带括号的用法更普遍，大多数程序员采用这种形式。　&nbsp;<br><br>　　<strong>注意：</strong>sizeof操作符不能用于函数类型，不完全类型或位字段。不完全类型指具有未知存储大小的数据类型，如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。　&nbsp;<br><br>　　如sizeof(max)若此时变量max定义为int　max(),sizeof(char_v)　若此时char_v定义为char　char_v　[MAX]且MAX未知，sizeof(void)都不是正确形式。　&nbsp;<br><br><strong>三、sizeof的结果　</strong>&nbsp;<br>　　sizeof操作符的结果类型是size_t，它在头文件<br><br>中typedef为unsigned　int类型。该类型保证能容纳实现所建立的最大对象的字节大小。　&nbsp;<br><br>　　1、若操作数具有类型char、unsigned　char或signed　char，其结果等于1。　&nbsp;<br><br>　　ANSI　C正式规定字符类型为1字节。　&nbsp;<br><br>
2、int、unsigned　int　、short　int、unsigned　short　、long　int　、unsigned　long　、
&nbsp;float、double、long　double类型的sizeof　在ANSI　C中没有具体规定，大小依赖于实现，一般可能分别为2、2、2、
2、&nbsp;4、4、4、8、10。　&nbsp;<br><br>　　3、当操作数是指针时，sizeof依赖于编译器。例如Microsoft　C/C++7.0中，near类指针字节数为2，far、huge类指针字节数为4。一般Unix的指针字节数为4。　&nbsp;<br><br>　　4、当操作数具有数组类型时，其结果是数组的总字节数。　&nbsp;<br><br>　　5、联合类型操作数的sizeof是其最大字节成员的字节数。结构类型操作数的sizeof是这种类型对象的总字节数，包括任何垫补在内。　&nbsp;<br><br>　　让我们看如下结构：　&nbsp;<br><br>　　struct　{char　b;　double　x;}　a;　&nbsp;<br><br>　　在某些机器上sizeof（a）=12，而一般sizeof（char）+　sizeof（double）=9。　&nbsp;<br><br>　　这是因为编译器在考虑对齐问题时，在结构中插入空位以控制各成员对象的地址对齐。如double类型的结构成员x要放在被4整除的地址。　&nbsp;<br><br>　　6、如果操作数是函数中的数组形参或函数类型的形参，sizeof给出其指针的大小。　&nbsp;<br><br><strong>四、sizeof与其他操作符的关系　</strong>&nbsp;<br>　　sizeof的优先级为2级，比/、%等3级运算符优先级高。它可以与其他操作符一起组成表达式。如i*sizeof（int）；其中i为int类型变量。　&nbsp;<br><br><strong>五、sizeof的主要用途　</strong>&nbsp;<br>　　1、sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。例如：　&nbsp;<br><br>　　void　*malloc（size_t　size）,　&nbsp;<br><br>　　size_t　fread(void　*　ptr,size_t　size,size_t　nmemb,FILE　*　stream)。　&nbsp;<br><br>　　2、sizeof的另一个的主要用途是计算数组中元素的个数。例如：　&nbsp;<br><br>　　void　*　memset（void　*　s,int　c,sizeof(s)）。　&nbsp;<br><br><strong>六、建议　</strong>&nbsp;<br>　　由于操作数的字节数在实现时可能出现变化，建议在涉及到操作数字节大小时用sizeof来代替常量计算。<br><br><br><strong>=============================================================<br>本文主要包括二个部分，第一部分重点介绍在VC中，怎么样采用sizeof来求结构的大小，以及容易出现的问题，并给出解决问题的方法，第二部分总结出VC中sizeof的主要用法。&nbsp;<br><br>1、&nbsp;sizeof应用在结构上的情况</strong>&nbsp;<br><br>请看下面的结构：&nbsp;<br><br>struct&nbsp;MyStruct&nbsp;<br><br>{&nbsp;<br><br>double&nbsp;dda1;&nbsp;<br><br>char&nbsp;dda;&nbsp;<br><br>int&nbsp;type&nbsp;<br><br>};&nbsp;<br><br>对结构MyStruct采用sizeof会出现什么结果呢？sizeof(MyStruct)为多少呢？也许你会这样求：&nbsp;<br><br>sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13&nbsp;<br><br>但是当在VC中测试上面结构的大小时，你会发现sizeof(MyStruct)为16。你知道为什么在VC中会得出这样一个结果吗？&nbsp;<br><br>其
实，这是VC对变量存储的一个特殊处理。为了提高CPU的存储速度，VC对一些变量的起始地址做了"对齐"处理。在默认情况下，VC规定各成员变量存放的
起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式(vc6.0,32位系统)。&nbsp;<br><br>类型&nbsp;<br>对齐方式（变量存放的起始地址相对于结构的起始地址的偏移量）&nbsp;<br><br>Char&nbsp;<br>偏移量必须为sizeof(char)即1的倍数&nbsp;<br><br>int&nbsp;<br>偏移量必须为sizeof(int)即4的倍数&nbsp;<br><br>float&nbsp;<br>偏移量必须为sizeof(float)即4的倍数&nbsp;<br><br>double&nbsp;<br>偏移量必须为sizeof(double)即8的倍数&nbsp;<br><br>Short&nbsp;<br>偏移量必须为sizeof(short)即2的倍数&nbsp;<br><br><br>各
成员变量在存放的时候根据在结构中出现的顺序依次申请空间，同时按照上面的对齐方式调整位置，空缺的字节VC会自动填充。同时VC为了确保结构的大小为结
构的字节边界数（即该结构中占用最大空间的类型所占用的字节数）的倍数，所以在为最后一个成员变量申请空间后，还会根据需要自动填充空缺的字节。&nbsp;<br><br>下面用前面的例子来说明VC到底怎么样来存放结构的。&nbsp;<br><br>struct&nbsp;MyStruct&nbsp;<br><br>{&nbsp;<br><br>double&nbsp;dda1;&nbsp;<br><br>char&nbsp;dda;&nbsp;<br><br>int&nbsp;type&nbsp;<br><br>}；&nbsp;<br><br>为
上面的结构分配空间的时候，VC根据成员变量出现的顺序和对齐方式，先为第一个成员dda1分配空间，其起始地址跟结构的起始地址相同（刚好偏移量0刚好
为sizeof(double)的倍数），该成员变量占用sizeof(double)=8个字节；接下来为第二个成员dda分配空间，这时下一个可以分
配的地址对于结构的起始地址的偏移量为8，是sizeof(char)的倍数，所以把dda存放在偏移量为8的地方满足对齐方式，该成员变量占用
&nbsp;sizeof(char)=1个字节；接下来为第三个成员type分配空间，这时下一个可以分配的地址对于结构的起始地址的偏移量为9，不是
sizeof&nbsp;(int)=4的倍数，为了满足对齐方式对偏移量的约束问题，VC自动填充3个字节（这三个字节没有放什么东西），这时下一个可以分配的地
址对于结构的起始地址的偏移量为12，刚好是sizeof(int)=4的倍数，所以把type存放在偏移量为12的地方，该成员变量占用sizeof
(int)=4个字节；这时整个结构的成员变量已经都分配了空间，总的占用的空间大小为：8+1+3+4=16，刚好为结构的字节边界数（即结构中占用最
大空间的类型所占用的字节数sizeof(double)=8）的倍数，所以没有空缺的字节需要填充。所以整个结构的大小为：sizeof
(MyStruct)=8+1+&nbsp;3+4=16，其中有3个字节是VC自动填充的，没有放任何有意义的东西。&nbsp;<br><br>下面再举个例子，交换一下上面的MyStruct的成员变量的位置，使它变成下面的情况：&nbsp;<br><br>struct&nbsp;MyStruct&nbsp;<br><br>{&nbsp;<br><br>char&nbsp;dda;&nbsp;<br><br>double&nbsp;dda1;&nbsp;&nbsp;&nbsp;<br><br>int&nbsp;type&nbsp;<br><br>}；&nbsp;<br><br>这个结构占用的空间为多大呢？在VC6.0环境下，可以得到sizeof(MyStruc)为24。结合上面提到的分配空间的一些原则，分析下VC怎么样为上面的结构分配空间的。（简单说明）&nbsp;<br><br>struct&nbsp;MyStruct&nbsp;<br><br>{&nbsp;<br><br>&nbsp;&nbsp;char&nbsp;dda;//偏移量为0，满足对齐方式，dda占用1个字节；&nbsp;<br><br>double&nbsp;dda1;//下一个可用的地址的偏移量为1，不是sizeof(double)=8&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//的倍数，需要补足7个字节才能使偏移量变为8（满足对齐&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//方式），因此VC自动填充7个字节，dda1存放在偏移量为8&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//的地址上，它占用8个字节。&nbsp;<br><br>int&nbsp;type；//下一个可用的地址的偏移量为16，是sizeof(int)=4的倍&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//数，满足int的对齐方式，所以不需要VC自动填充，type存&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//放在偏移量为16的地址上，它占用4个字节。&nbsp;<br><br>}；//所有成员变量都分配了空间，空间总的大小为1+7+8+4=20，不是结构&nbsp;<br><br>&nbsp;&nbsp;&nbsp;//的节边界数（即结构中占用最大空间的类型所占用的字节数sizeof&nbsp;<br><br>&nbsp;&nbsp;&nbsp;//(double)=8）的倍数，所以需要填充4个字节，以满足结构的大小为&nbsp;<br><br>&nbsp;&nbsp;&nbsp;//sizeof(double)=8的倍数。&nbsp;<br><br><br>所以该结构总的大小为：sizeof(MyStruc)为1+7+8+4+4=24。其中总的有7+4=11个字节是VC自动填充的，没有放任何有意义的东西。&nbsp;<br><br><br>VC对结构的存储的特殊处理确实提高CPU存储变量的速度，但是有时候也带来了一些麻烦，我们也屏蔽掉变量默认的对齐方式，自己可以设定变量的对齐方式。&nbsp;<br></span></p>
<p><strong>#pragma pack(n)</strong><br>VC&nbsp;
中提供了#pragma&nbsp;pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况：第一、如果n大于等于该变
量所占用的字节数，那么偏移量必须满足默认的对齐方式，第二、如果n小于该变量的类型所占用的字节数，那么偏移量为n的倍数，不用满足默认的对齐方式。结
构的总大小也有个约束条件，分下面两种情况：如果n大于所有成员变量类型所占用的字节数，那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数；
&nbsp;&nbsp;<br><br>否则必须为n的倍数。下面举例说明其用法。&nbsp;<br><br>#pragma&nbsp;pack(push)&nbsp;//保存对齐状态&nbsp;<br><br>#pragma&nbsp;pack(4)//设定为4字节对齐&nbsp;<br><br>struct&nbsp;test&nbsp;<br><br>{&nbsp;<br><br>&nbsp;&nbsp;char&nbsp;m1;&nbsp;<br><br>&nbsp;&nbsp;double&nbsp;m4;&nbsp;<br><br>&nbsp;&nbsp;int&nbsp;&nbsp;m3;&nbsp;<br><br>};&nbsp;<br><br>#pragma&nbsp;pack(pop)//恢复对齐状态&nbsp;<br><br>以
上结构的大小为16，下面分析其存储情况，首先为m1分配空间，其偏移量为0，满足我们自己设定的对齐方式（4字节对齐），m1占用1个字节。接着开始为
&nbsp;m4分配空间，这时其偏移量为1，需要补足3个字节，这样使偏移量满足为n=4的倍数（因为sizeof(double)大于n）,m4占用8个字节。
接着为m3分配空间，这时其偏移量为12，满足为4的倍数，m3占用4个字节。这时已经为所有成员变量分配了空间，共分配了16个字节，满足为n的倍数。
如果把上面的#pragma&nbsp;pack(4)改为#pragma&nbsp;pack(16)，那么我们可以得到结构的大小为24。（请读者自己分析）&nbsp;<br><br><strong>2、&nbsp;sizeof用法总结</strong>&nbsp;<br><br>在VC中，sizeof有着许多的用法，而且很容易引起一些错误。下面根据sizeof后面的参数对sizeof的用法做个总结。&nbsp;<br><br>A．&nbsp;&nbsp;参数为数据类型或者为一般变量。例如sizeof(int),sizeof(long)等等。这种情况要注意的是不同系统系统或者不同编译器得到的结果可能是不同的。例如int类型在16位系统中占2个字节，在32位系统中占4个字节。&nbsp;<br><br>B．&nbsp;&nbsp;参数为数组或指针。下面举例说明.&nbsp;<br><br>int&nbsp;a[50];&nbsp;&nbsp;//sizeof(a)=4*50=200;&nbsp;求数组所占的空间大小&nbsp;<br><br>int&nbsp;*a=new&nbsp;int[50];//&nbsp;sizeof(a)=4;&nbsp;a为一个指针，sizeof(a)是求指针&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//的大小,在32位系统中，当然是占4个字节。&nbsp;<br><br>C．&nbsp;&nbsp;参数为结构或类。Sizeof应用在类和结构的处理情况是相同的。但有两点需要注意，第一、结构或者类中的静态成员不对结构或者类的大小产生影响，因为静态变量的存储位置与结构或者类的实例地址无关。&nbsp;<br><br>第二、没有成员变量的结构或类的大小为1，因为必须保证结构或类的每一&nbsp;<br><br>个实例在内存中都有唯一的地址。&nbsp;<br><br>下面举例说明，&nbsp;<br><br>Class&nbsp;Test{int&nbsp;a;static&nbsp;double&nbsp;c};//sizeof(Test)=4.&nbsp;<br><br>Test&nbsp;*s;//sizeof(s)=4,s为一个指针。&nbsp;<br><br>Class&nbsp;test1{&nbsp;};//sizeof(test1)=1;&nbsp;<br><br>D．&nbsp;&nbsp;参数为其他。下面举例说明。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;int&nbsp;func(char&nbsp;s[5]);&nbsp;<br><br>&nbsp;&nbsp;&nbsp;{&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;sizeof(s);//这里将输出4，本来s为一个数组，但由于做为函&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//数的参数在传递的时候系统处理为一个指针，所&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//以sizeof(s)实际上为求指针的大小。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;1;&nbsp;<br><br>}&nbsp;<br><br>sizeof(func("1234"))=4//因为func的返回类型为int，所以相当于&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//求sizeof(int).&nbsp;<br><br><br>以上为sizeof的基本用法，在实际的使用中要注意分析VC的分配变量的分配策略，这样的话可以避免一些错误。<br>&nbsp;</p><img src ="http://www.cppblog.com/sgq116300/aggbug/36576.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sgq116300/" target="_blank">sunGuoqin</a> 2007-11-14 12:35 <a href="http://www.cppblog.com/sgq116300/archive/2007/11/14/36576.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内核printf源代码分析 </title><link>http://www.cppblog.com/sgq116300/archive/2007/11/14/36575.html</link><dc:creator>sunGuoqin</dc:creator><author>sunGuoqin</author><pubDate>Wed, 14 Nov 2007 04:27:00 GMT</pubDate><guid>http://www.cppblog.com/sgq116300/archive/2007/11/14/36575.html</guid><wfw:comment>http://www.cppblog.com/sgq116300/comments/36575.html</wfw:comment><comments>http://www.cppblog.com/sgq116300/archive/2007/11/14/36575.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/sgq116300/comments/commentRss/36575.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sgq116300/services/trackbacks/36575.html</trackback:ping><description><![CDATA[<span id="ArticleContent1_ArticleContent1_lblContent">
<p>打开Source Insight来阅读EduOS的源代码,我们在stdio.c里找到了printf的实现代码.首先看看对printf的定义:<br>[code]<br>int printf (const char *cntrl_string, ...)<br>[/code]<br>第一个参数cntrl_string是控制字符串,也就是平常我们写入%d,%f的地方.紧接着后面是一个变长参数.</p>
<p>看看函数头部的定义:</p>
<p>&nbsp; [code]int pos = 0, cnt_printed_chars = 0, i; <br>&nbsp; unsigned char* chptr;<br>&nbsp; va_list ap;[/code]<br>马上晕!除了ap我们可以马上判断出来是用来读取变长参数的,i用于循环变量.其他变量都不知道是怎么回事.不要着急,我们边看代码边分析.代码的第一行必然是</p>
<p>[code]va_start (ap, cntrl_string);[/code]<br>用来初始化变长参数.</p>
<p>接下来是一个while循环</p>
<p>[code]while (cntrl_string[pos]) {<br>...<br>}[/code]</p>
<p>结束条件是cntrl_string[pos]为NULL,显然这个循环是用来遍历整个控制字符串的.自然pos就是当前遍历到的位置了.进入循环首先闯入视线的是</p>
<p>[code] if (cntrl_string[pos] == '%') {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pos++;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>&nbsp;} [/code]</p>
<p>开门见山,上来就当前字符是否办断是否%.一猜就知道如果成立pos++马上取出下一个字符在d,f,l等等之间进行判断.往下一看,果真不出所料:</p>
<p>[code]switch (cntrl_string[pos]) {<br>&nbsp;&nbsp;&nbsp; case 'c':<br>...<br>&nbsp;&nbsp;&nbsp; case 's':<br>...<br>&nbsp;&nbsp;&nbsp; case 'i':<br>...<br>&nbsp;&nbsp;&nbsp; case 'd':<br>...<br>&nbsp;&nbsp;&nbsp; case 'u':<br>...[/code]</p>
<p>用上switch-case了. 快速浏览一下下面的代码.</p>
<p>首先看看case 'c'的部分</p>
<p>[code]case 'c':<br>&nbsp;putchar (va_arg (ap, unsigned char));<br>&nbsp;cnt_printed_chars++;<br>&nbsp;break;[/code]</p>
<p>%c表示仅仅输出一个字符.因此先通过va_arg进行参数的类型转换,之后用putchar[1]输出到屏幕上去.之后是<br>cnt_printed_chars++,通过这句我们就可以判断出cnt_printed_chars使用来表示,已经被printf输出的字符个数的.</p>
<p>再来看看 case 's':<br>[code]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 's':<br>&nbsp;chptr = va_arg (ap, unsigned char*);<br>&nbsp;i = 0;<br>&nbsp;while (chptr [i]) {<br>&nbsp;&nbsp; cnt_printed_chars++;<br>&nbsp;&nbsp; putchar (chptr [i++]);<br>&nbsp;}<br>&nbsp;break;[/code]和case 'c',同出一辙.cnt_printed_chars++放在了循环内,也证明了刚才提到的他的作用.另外我们也看到了cnptr是用来在处理字符串时的位置指针.到此为止,我们清楚的所有变量的用途,前途变得更加光明了.</p>
<p>接下来:<br>[code]// PartI<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 'i':<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 'd':<br>&nbsp;cnt_printed_chars += printInt (va_arg (ap, int));<br>&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 'u':<br>&nbsp;cnt_printed_chars += printUnsignedInt (va_arg (ap, unsigned int));<br>&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 'x':<br>&nbsp;cnt_printed_chars += printHexa (va_arg (ap, unsigned int), 'x');<br>&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 'X':<br>&nbsp;cnt_printed_chars += printHexa (va_arg (ap, unsigned int), 'X');<br>&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 'o':<br>&nbsp;cnt_printed_chars += printOctal (va_arg (ap, unsigned int));<br>&nbsp;break;<br>// Part II<br>&nbsp;case 'p':<br>&nbsp;putchar ('0');<br>&nbsp;putchar ('x');<br>&nbsp;cnt_printed_chars += 2; /* of '0x' */<br>&nbsp;cnt_printed_chars += printHexa (va_arg (ap, unsigned int), 'x');<br>&nbsp;break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case '#':<br>&nbsp;pos++;<br>&nbsp;switch (cntrl_string[pos]) {<br>&nbsp;case 'x':<br>&nbsp;&nbsp; putchar ('0');<br>&nbsp;&nbsp; putchar ('x');<br>&nbsp;&nbsp; cnt_printed_chars += 2; /* of '0x' */<br>&nbsp;&nbsp; cnt_printed_chars += printHexa (va_arg (ap, unsigned int), 'x');<br>&nbsp;&nbsp; break;<br>&nbsp;case 'X':<br>&nbsp;&nbsp; putchar ('0');<br>&nbsp;&nbsp; putchar ('X');<br>&nbsp;&nbsp; cnt_printed_chars += 2; /* of '0X' */<br>&nbsp;&nbsp; cnt_printed_chars += printHexa (va_arg (ap, unsigned int), 'X');<br>&nbsp;&nbsp; break;<br>&nbsp;case 'o':<br>&nbsp;&nbsp; putchar ('0');<br>&nbsp;&nbsp; cnt_printed_chars++;<br>&nbsp;&nbsp; cnt_printed_chars += printOctal (va_arg (ap, unsigned int));<br>&nbsp;&nbsp; break;[/code]<br>注意观察一下,PartII的代码其实就是比PartI的代码多一个样式.在16进制数或八进制前加入0x或是o,等等.因此这里就只分析一下PartI咯.</p>
<p>其实仔细看看PartI的个条case,也就是把参数分发到了更具体的函数用于显示,然后以返回值的形式返回输出个数.对于这些函数就不具体分析了.我们先来看看一些善后处理:</p>
<p>先看case的default处理.<br>[code]default:<br>&nbsp;putchar ((unsigned char) cntrl_string[pos]);<br>&nbsp;cnt_printed_chars++;[/code]就是直接输出cntrl_string里%号后面的未知字符.应该是一种容错设计处理.</p>
<p>再看看if (cntrl_string[pos] == '%')的else部分<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>[code]else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; putchar ((unsigned char) cntrl_string[pos]);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cnt_printed_chars++;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pos++;<br>&nbsp;}[/code]<br>如果不是%开头的,那么直接输出这个字符.</p>
<p>最后函数返回前<br>&nbsp; [code]va_end (ap);<br>&nbsp; return cnt_printed_chars;[/code]va_end处理变长参数的善后工作.并返回输出的字符个数.</p>
<p>在最后我们有必要谈谈putChar函数以及基本输出的基础函数printChar,先来看看putChar</p>
<p>[code]int putchar (int c) {<br>&nbsp; switch ((unsigned char) c) {<br>&nbsp; case '\n' :<br>&nbsp;&nbsp;&nbsp; newLine ();<br>&nbsp;&nbsp;&nbsp; break;<br>&nbsp; case '\r' :<br>&nbsp;&nbsp;&nbsp; carriageReturn ();<br>&nbsp;&nbsp;&nbsp; break;<br>&nbsp; case '\f' :<br>&nbsp;&nbsp;&nbsp; clearScreen ();<br>&nbsp;&nbsp;&nbsp; break;<br>&nbsp; case '\t' :<br>&nbsp;&nbsp;&nbsp; printChar (32); printChar (32); /* 32 = space */<br>&nbsp;&nbsp;&nbsp; printChar (32); printChar (32);<br>&nbsp;&nbsp;&nbsp; printChar (32); printChar (32); <br>&nbsp;&nbsp;&nbsp; printChar (32); printChar (32);<br>&nbsp;&nbsp;&nbsp; break;<br>&nbsp; case '\b':<br>&nbsp;&nbsp;&nbsp; backspace ();<br>&nbsp;&nbsp;&nbsp; break;<br>&nbsp; case '\a':<br>&nbsp;&nbsp;&nbsp; beep ();<br>&nbsp;&nbsp;&nbsp; break;<br>&nbsp; default :<br>&nbsp;&nbsp;&nbsp; printChar ((unsigned char) c);<br>&nbsp; }<br>&nbsp; return c;<br>}[/code]<br>通
览一下,也是switch-case为主体的.主要是用来应对一些特殊字符,如\n,\r,....这里需要提一下,关于\t的理解.有些人认为\t就是
8个space,有些人则认为,屏幕分为10大列(每个大列8个小列总共80列).一个\t就跳到下一个大列输出.也就是说不管你现在实在屏幕的第
1,2,3,4,5,6,7位置输出字符,只要一个\t都在第8个位置开始输出.
VS.NET中就是用的这种理解.因此如果按照这个理解的话,\t的实现可以这样</p>
<p>[code]int currentX = ((currentX % 10) + 1) * 8;[/code]</p>
<p>然后在currentX位置输出.</p>
<p>接下来看printChar也就是输出部分最低层的操作咯</p>
<p>[code]void printChar (const byte ch) {<br>&nbsp; *(word *)(VIDEO + y * 160 + x * 2) = ch | (fill_color &lt;&lt; 8); <br>&nbsp; x++;<br>&nbsp; if (x &gt;= WIDTH)<br>&nbsp;&nbsp;&nbsp; newLine ();<br>&nbsp; setVideoCursor (y, x);<br>}[/code]
这里VIDEO表示显存地址也就是0xB8000.通过 y * 160 + x
屏幕(x,y)坐标在显存中的位置.这里需要知道,一个字符显示需要两个字节,一个是ASCII码,第二个是字符属性代码也就是颜色代码.因此才必须
y * 80 * 2 + x = y * 160 + x.那么ch | (fill_color &lt;&lt;
8)也自然就是写入字符及属性代码用的了.每写一个字符光标位置加1,如果大于屏幕宽度WIDTH就换行.最后通过setVideoCursor设置新的
光标位置.完成了整个printChar过程.</p>
</span>  <img src ="http://www.cppblog.com/sgq116300/aggbug/36575.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sgq116300/" target="_blank">sunGuoqin</a> 2007-11-14 12:27 <a href="http://www.cppblog.com/sgq116300/archive/2007/11/14/36575.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>