??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品高清国产一久久,久久噜噜电影你懂的,99久久久精品http://m.shnenglu.com/sgq116300/category/5555.htmlSun Guoqing的Blogzh-cnTue, 20 May 2008 02:56:44 GMTTue, 20 May 2008 02:56:44 GMT60关于sizeof()的简单解? http://m.shnenglu.com/sgq116300/archive/2007/11/14/36576.htmlsunGuoqinsunGuoqinWed, 14 Nov 2007 04:35:00 GMThttp://m.shnenglu.com/sgq116300/archive/2007/11/14/36576.htmlhttp://m.shnenglu.com/sgq116300/comments/36576.htmlhttp://m.shnenglu.com/sgq116300/archive/2007/11/14/36576.html#Feedback7http://m.shnenglu.com/sgq116300/comments/commentRss/36576.htmlhttp://m.shnenglu.com/sgq116300/services/trackbacks/36576.html在所有说明之前,l大家出一道题目:(x)

int a=256;

printf("%d\n", sizeof(++a));

printf("%d\n", a);

那么到底打印的是多少呢?

应该??56Q我想第一个答案大家应该已l没有问题了Q但是ؓ(f)什么在++a以后Qa的数D是没有发生变化呢Q因为sizeofQ)是一个运符Q在其中的所有的q算都是无效的,所?+aҎ(gu)没有运行?/p>

上面的一个例子提醒我们,虽然sizeof看这单,但是其中q是有很多的问题值得讨论的,呵呵?br>

一、sizeof的概?/strong>  
  sizeof是C语言的一U单目操作符Q如C语言的其他操作符++?-{。它q不是函数。sizeof操作W以字节形式l出了其操作数的存储大小?span class="Title">操作数可以是一个表辑ּ或括在括号内的类型名。操作数的存储大由操作数的cd军_。  

二、sizeof的用方法  
  1、用于数据类型  

  sizeof使用形式QsizeofQtypeQ  

  数据cd必须用括h住。如sizeofQintQ。  

  2、用于变量  

  sizeof使用形式QsizeofQvar_nameQ或sizeof var_name  

  变量名可以不用括h住。如sizeof (var_name)Qsizeof var_name{都是正Ş式。带括号的用法更普遍Q大多数E序员采用这UŞ式。  

  注意Q?/strong>sizeof操作W不能用于函数类型,不完全类型或位字Dc不完全cd指具有未知存储大的数据cdQ如未知存储大小的数l类型、未知内容的l构或联合类型、voidcd{。  

  如sizeof(max)若此时变量max定义为int max(),sizeof(char_v) 若此时char_v定义为char char_v [MAX]且MAX未知Qsizeof(void)都不是正Ş式。  

三、sizeof的结果  
  sizeof操作W的l果cd是size_tQ它在头文g

中typedef为unsigned intcd。该cd保证能容U_现所建立的最大对象的字节大小。  

  1、若操作数具有类型char、unsigned char或signed charQ其l果{于1。  

  ANSI C正式规定字符cd?字节。  

2、int、unsigned int 、short int、unsigned short 、long int 、unsigned long ?  float、double、long doublecd的sizeof 在ANSI C中没有具体规定,大小依赖于实玎ͼ一般可能分别ؓ(f)2??? 2?nbsp;4????0。  

  3、当操作数是指针Ӟsizeof依赖于编译器。例如Microsoft C/C++7.0中,nearcL针字节数?Qfar、hugecL针字节数?。一般Unix的指针字节数?。  

  4、当操作数具有数l类型时Q其l果是数l的d节数。  

  5、联合类型操作数的sizeof是其最大字节成员的字节数。结构类型操作数的sizeof是这U类型对象的d节数Q包括Q何垫补在内。  

  让我们看如下l构Q  

  struct {char b; double x;} a;  

  在某些机器上sizeofQaQ?12Q而一般sizeofQcharQ? sizeofQdoubleQ?9。  

  q是因ؓ(f)~译器在考虑寚w问题Ӟ在结构中插入IZ以控制各成员对象的地址寚w。如doublecd的结构成员x要放在被4整除的地址。  

  6、如果操作数是函C的数lŞ参或函数cd的Ş参,sizeofl出其指针的大小。  

四、sizeof与其他操作符的关pR 
  sizeof的优先?U,??{?U运符优先U高。它可以与其他操作符一L(fng)成表辑ּ。如i*sizeofQintQ;其中i为intcd变量。  

五、sizeof的主要用途  
  1、sizeof操作W的一个主要用途是与存储分配和I/Opȝ那样的例E进行通信。例如:(x)  

  void *mallocQsize_t sizeQ?  

  size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。  

  2、sizeof的另一个的主要用途是计算数组中元素的个数。例如:(x)  

  void * memsetQvoid * s,int c,sizeof(s)Q。  

六、徏议  
  ׃操作数的字节数在实现时可能出现变化,在涉?qing)到操作数字节大时用sizeof来代替常量计?br>

=============================================================
本文主要包括二个部分Q第一部分重点介绍在VC中,怎么样采用sizeof来求l构的大,以及(qing)Ҏ(gu)出现的问题,q给决问题的Ҏ(gu)Q第二部分ȝ出VC中sizeof的主要用法?nbsp;

1?nbsp;sizeof应用在结构上的情?/strong> 

L(fng)下面的结构:(x) 

struct MyStruct 



double dda1; 

char dda; 

int type 

}; 

对结构MyStruct采用sizeof?x)出C么结果呢Qsizeof(MyStruct)为多呢Q也怽?x)这hQ?nbsp;

sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13 

但是当在VC中测试上面结构的大小Ӟ你会(x)发现sizeof(MyStruct)?6。你知道Z么在VC中会(x)得出q样一个结果吗Q?nbsp;

? 实,q是VC对变量存储的一个特D处理。ؓ(f)了提高CPU的存储速度QVC对一些变量的起始地址做了"寚w"处理。在默认情况下,VC规定各成员变量存攄 起始地址相对于结构的起始地址的偏U量必须变量的类型所占用的字节数的倍数。下面列出常用类型的寚w方式(vc6.0,32位系l??nbsp;

cd 
寚w方式Q变量存攄起始地址相对于结构的起始地址的偏U量Q?nbsp;

Char 
偏移量必Mؓ(f)sizeof(char)?的倍数 

int 
偏移量必Mؓ(f)sizeof(int)?的倍数 

float 
偏移量必Mؓ(f)sizeof(float)?的倍数 

double 
偏移量必Mؓ(f)sizeof(double)?的倍数 

Short 
偏移量必Mؓ(f)sizeof(short)?的倍数 


? 成员变量在存攄时候根据在l构中出现的序依次甌I间Q同时按照上面的寚w方式调整位置Q空~的字节VC?x)自动填充。同时VCZ保l构的大ؓ(f)l? 构的字节边界敎ͼ卌l构中占用最大空间的cd所占用的字节数Q的倍数Q所以在为最后一个成员变量申L(fng)间后Q还?x)根据需要自动填充空~的字节?nbsp;

下面用前面的例子来说明VC到底怎么h存放l构的?nbsp;

struct MyStruct 



double dda1; 

char dda; 

int type 

}Q?nbsp;

? 上面的结构分配空间的时候,VCҎ(gu)成员变量出现的顺序和寚w方式Q先为第一个成员dda1分配I间Q其起始地址跟结构的起始地址相同Q刚好偏U量0刚好 为sizeof(double)的倍数Q,该成员变量占用sizeof(double)=8个字节;接下来ؓ(f)W二个成员dda分配I间Q这时下一个可以分 配的地址对于l构的v始地址的偏U量?Q是sizeof(char)的倍数Q所以把dda存放在偏U量?的地Ҏ(gu)_齐方式,该成员变量占?  sizeof(char)=1个字节;接下来ؓ(f)W三个成员type分配I间Q这时下一个可以分配的地址对于l构的v始地址的偏U量?Q不? sizeof (int)=4的倍数Qؓ(f)了满_齐方式对偏移量的U束问题QVC自动填充3个字节(q三个字节没有放什么东西)Q这时下一个可以分配的? 址对于l构的v始地址的偏U量?2Q刚好是sizeof(int)=4的倍数Q所以把type存放在偏U量?2的地方,该成员变量占用sizeof (int)=4个字节;q时整个l构的成员变量已l都分配了空_(d)ȝ占用的空间大ؓ(f)Q?+1+3+4=16Q刚好ؓ(f)l构的字节边界数Q即l构中占用最 大空间的cd所占用的字节数sizeof(double)=8Q的倍数Q所以没有空~的字节需要填充。所以整个结构的大小为:(x)sizeof (MyStruct)=8+1+ 3+4=16Q其中有3个字节是VC自动填充的,没有放Q何有意义的东ѝ?nbsp;

下面再D个例子,交换一下上面的MyStruct的成员变量的位置Q它变成下面的情况Q?nbsp;

struct MyStruct 



char dda; 

double dda1;   

int type 

}Q?nbsp;

q个l构占用的空间ؓ(f)多大呢?在VC6.0环境下,可以得到sizeof(MyStruc)?4。结合上面提到的分配I间的一些原则,分析下VC怎么样ؓ(f)上面的结构分配空间的。(单说明) 

struct MyStruct 



  char dda;//偏移量ؓ(f)0Q满_齐方式,dda占用1个字节; 

double dda1;//下一个可用的地址的偏U量?Q不是sizeof(double)=8 

             //的倍数Q需要补?个字节才能偏移量变?Q满_?nbsp;

             //方式Q,因此VC自动填充7个字节,dda1存放在偏U量? 

             //的地址上,它占?个字节?nbsp;

int typeQ?/下一个可用的地址的偏U量?6Q是sizeof(int)=4的?nbsp;

           //敎ͼ满int的对齐方式,所以不需要VC自动填充Qtype?nbsp;

           //攑֜偏移量ؓ(f)16的地址上,它占?个字节?nbsp;

}Q?/所有成员变量都分配了空_(d)I间ȝ大小?+7+8+4=20Q不是结?nbsp;

   //的节边界敎ͼ即结构中占用最大空间的cd所占用的字节数sizeof 

   //(double)=8Q的倍数Q所以需要填?个字节,以满结构的大小?nbsp;

   //sizeof(double)=8的倍数?nbsp;


所以该l构ȝ大小为:(x)sizeof(MyStruc)?+7+8+4+4=24。其中ȝ?+4=11个字节是VC自动填充的,没有放Q何有意义的东ѝ?nbsp;


VC对结构的存储的特D处理确实提高CPU存储变量的速度Q但是有时候也带来了一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以讑֮变量的对齐方式?nbsp;

#pragma pack(n)
VC  中提供了#pragma pack(n)来设定变量以n字节寚w方式。n字节寚w是说变量存攄起始地址的偏U量有两U情况:(x)W一、如果n大于{于该变 量所占用的字节数Q那么偏U量必须满默认的对齐方式,W二、如果n于该变量的cd所占用的字节数Q那么偏U量为n的倍数Q不用满默认的寚w方式。结 构的d也有个U束条gQ分下面两种情况Q如果n大于所有成员变量类型所占用的字节数Q那么结构的d必Mؓ(f)占用I间最大的变量占用的空间数的倍数Q?   

否则必须为n的倍数。下面D例说明其用法?nbsp;

#pragma pack(push) //保存寚w状?nbsp;

#pragma pack(4)//讑֮?字节寚w 

struct test 



  char m1; 

  double m4; 

  int  m3; 

}; 

#pragma pack(pop)//恢复寚w状?nbsp;

? 上结构的大小?6Q下面分析其存储情况Q首先ؓ(f)m1分配I间Q其偏移量ؓ(f)0Q满x们自p定的寚w方式Q?字节寚wQ,m1占用1个字节。接着开始ؓ(f)  m4分配I间Q这时其偏移量ؓ(f)1Q需要补?个字节,q样使偏U量满为n=4的倍数Q因为sizeof(double)大于nQ?m4占用8个字节? 接着为m3分配I间Q这时其偏移量ؓ(f)12Q满ؓ(f)4的倍数Qm3占用4个字节。这时已lؓ(f)所有成员变量分配了I间Q共分配?6个字节,满为n的倍数? 如果把上面的#pragma pack(4)改ؓ(f)#pragma pack(16)Q那么我们可以得到结构的大小?4。(误者自己分析) 

2?nbsp;sizeof用法ȝ 

在VC中,sizeof有着许多的用法,而且很容易引起一些错误。下面根据sizeof后面的参数对sizeof的用法做个ȝ?nbsp;

AQ?nbsp; 参数为数据类型或者ؓ(f)一般变量。例如sizeof(int),sizeof(long){等。这U情况要注意的是不同pȝpȝ或者不同编译器得到的结果可能是不同的。例如intcd?6位系l中?个字节,?2位系l中?个字节?nbsp;

BQ?nbsp; 参数为数l或指针。下面D例说? 

int a[50];  //sizeof(a)=4*50=200; 求数l所占的I间大小 

int *a=new int[50];// sizeof(a)=4; aZ个指针,sizeof(a)是求指针 

                   //的大??2位系l中Q当然是?个字节?nbsp;

CQ?nbsp; 参数为结构或cRSizeof应用在类和结构的处理情况是相同的。但有两炚w要注意,W一、结构或者类中的静态成员不对结构或者类的大生媄响,因ؓ(f)静态变量的存储位置与结构或者类的实例地址无关?nbsp;

W二、没有成员变量的l构或类的大ؓ(f)1Q因为必M证结构或cȝ每一 

个实例在内存中都有唯一的地址?nbsp;

下面举例说明Q?nbsp;

Class Test{int a;static double c};//sizeof(Test)=4. 

Test *s;//sizeof(s)=4,sZ个指针?nbsp;

Class test1{ };//sizeof(test1)=1; 

DQ?nbsp; 参数为其他。下面D例说明?nbsp;

   int func(char s[5]); 

   { 

     cout<<sizeof(s);//q里输?Q本来sZ个数l,但由于做为函 

                     //数的参数在传递的时候系l处理ؓ(f)一个指针,所 

                     //以sizeof(s)实际上ؓ(f)求指针的大小?nbsp;

     return 1; 



sizeof(func("1234"))=4//因ؓ(f)func的返回类型ؓ(f)intQ所以相当于 

                     //求sizeof(int). 


以上为sizeof的基本用法,在实际的使用中要注意分析VC的分配变量的分配{略Q这L(fng)话可以避免一些错误?br> 



sunGuoqin 2007-11-14 12:35 发表评论
]]>
内核printf源代码分?http://m.shnenglu.com/sgq116300/archive/2007/11/14/36575.htmlsunGuoqinsunGuoqinWed, 14 Nov 2007 04:27:00 GMThttp://m.shnenglu.com/sgq116300/archive/2007/11/14/36575.htmlhttp://m.shnenglu.com/sgq116300/comments/36575.htmlhttp://m.shnenglu.com/sgq116300/archive/2007/11/14/36575.html#Feedback3http://m.shnenglu.com/sgq116300/comments/commentRss/36575.htmlhttp://m.shnenglu.com/sgq116300/services/trackbacks/36575.html

打开Source Insight来阅读EduOS的源代码,我们在stdio.c里找Cprintf的实C?首先看看对printf的定?
[code]
int printf (const char *cntrl_string, ...)
[/code]
W一个参数cntrl_string是控制字W串,也就是^常我们写?d,%f的地?紧接着后面是一个变长参?

看看函数头部的定?

  [code]int pos = 0, cnt_printed_chars = 0, i;
  unsigned char* chptr;
  va_list ap;[/code]
马上?除了ap我们可以马上判断出来是用来读取变长参数的,i用于循环变量.其他变量都不知道是怎么回事.不要着?我们边看代码边分?代码的第一行必然是

[code]va_start (ap, cntrl_string);[/code]
用来初始化变长参?

接下来是一个while循环

[code]while (cntrl_string[pos]) {
...
}[/code]

l束条g是cntrl_string[pos]为NULL,昄q个循环是用来遍历整个控制字W串?自然pos是当前遍历到的位置?q入循环首先闯入视线的是

[code] if (cntrl_string[pos] == '%') {
      pos++;
      ...
 } [/code]

开门见?上来当前字W是否办断是?.一猜就知道如果成立pos++马上取出下一个字W在d,f,l{等之间q行判断.往下一?果真不出所?

[code]switch (cntrl_string[pos]) {
    case 'c':
...
    case 's':
...
    case 'i':
...
    case 'd':
...
    case 'u':
...[/code]

用上switch-case? 快速浏览一下下面的代码.

首先看看case 'c'的部?/p>

[code]case 'c':
 putchar (va_arg (ap, unsigned char));
 cnt_printed_chars++;
 break;[/code]

%c表示仅仅输出一个字W?因此先通过va_argq行参数的类型{?之后用putchar[1]输出到屏q上?之后?br>cnt_printed_chars++,通过q句我们可以判断出cnt_printed_chars使用来表C?已经被printf输出的字W个数的.

再来看看 case 's':
[code]      case 's':
 chptr = va_arg (ap, unsigned char*);
 i = 0;
 while (chptr [i]) {
   cnt_printed_chars++;
   putchar (chptr [i++]);
 }
 break;[/code]和case 'c',同出一?cnt_printed_chars++攑֜了@环内,也证明了刚才提到的他的作?另外我们也看Ccnptr是用来在处理字符串时的位|指?到此为止,我们清楚的所有变量的用?前途变得更加光明了.

接下?
[code]// PartI
      case 'i':
      case 'd':
 cnt_printed_chars += printInt (va_arg (ap, int));
 break;
      case 'u':
 cnt_printed_chars += printUnsignedInt (va_arg (ap, unsigned int));
 break;
      case 'x':
 cnt_printed_chars += printHexa (va_arg (ap, unsigned int), 'x');
 break;
      case 'X':
 cnt_printed_chars += printHexa (va_arg (ap, unsigned int), 'X');
 break;
      case 'o':
 cnt_printed_chars += printOctal (va_arg (ap, unsigned int));
 break;
// Part II
 case 'p':
 putchar ('0');
 putchar ('x');
 cnt_printed_chars += 2; /* of '0x' */
 cnt_printed_chars += printHexa (va_arg (ap, unsigned int), 'x');
 break;
      case '#':
 pos++;
 switch (cntrl_string[pos]) {
 case 'x':
   putchar ('0');
   putchar ('x');
   cnt_printed_chars += 2; /* of '0x' */
   cnt_printed_chars += printHexa (va_arg (ap, unsigned int), 'x');
   break;
 case 'X':
   putchar ('0');
   putchar ('X');
   cnt_printed_chars += 2; /* of '0X' */
   cnt_printed_chars += printHexa (va_arg (ap, unsigned int), 'X');
   break;
 case 'o':
   putchar ('0');
   cnt_printed_chars++;
   cnt_printed_chars += printOctal (va_arg (ap, unsigned int));
   break;[/code]
注意观察一?PartII的代码其实就是比PartI的代码多一个样??6q制数或八进制前加入0x或是o,{等.因此q里只分析一下PartI?

其实仔细看看PartI的个条case,也就是把参数分发C更具体的函数用于昄,然后以返回值的形式q回输出个数.对于q些函数׃具体分析?我们先来看看一些善后处?

先看case的default处理.
[code]default:
 putchar ((unsigned char) cntrl_string[pos]);
 cnt_printed_chars++;[/code]是直接输出cntrl_string?号后面的未知字符.应该是一U容错设计处?

再看看if (cntrl_string[pos] == '%')的else部分
     
[code]else {
      putchar ((unsigned char) cntrl_string[pos]);
      cnt_printed_chars++;
      pos++;
 }[/code]
如果不是%开头的,那么直接输出q个字符.

最后函数返回前
  [code]va_end (ap);
  return cnt_printed_chars;[/code]va_end处理变长参数的善后工?q返回输出的字符个数.

在最后我们有必要谈谈putChar函数以及(qing)基本输出的基函数printChar,先来看看putChar

[code]int putchar (int c) {
  switch ((unsigned char) c) {
  case '\n' :
    newLine ();
    break;
  case '\r' :
    carriageReturn ();
    break;
  case '\f' :
    clearScreen ();
    break;
  case '\t' :
    printChar (32); printChar (32); /* 32 = space */
    printChar (32); printChar (32);
    printChar (32); printChar (32);
    printChar (32); printChar (32);
    break;
  case '\b':
    backspace ();
    break;
  case '\a':
    beep ();
    break;
  default :
    printChar ((unsigned char) c);
  }
  return c;
}[/code]
? 览一?也是switch-caseZ体的.主要是用来应对一些特D字W?如\n,\r,....q里需要提一?关于\t的理?有些为\t是 8个space,有些人则认ؓ(f),屏幕分ؓ(f)10大列(每个大列8个小列d80?.一个\tpC一个大列输?也就是说不管你现在实在屏q的W? 1,2,3,4,5,6,7位置输出字符,只要一个\t都在W?个位|开始输? VS.NET中就是用的这U理?因此如果按照q个理解的话,\t的实现可以这?/p>

[code]int currentX = ((currentX % 10) + 1) * 8;[/code]

然后在currentX位置输出.

接下来看printChar也就是输出部分最低层的操作咯

[code]void printChar (const byte ch) {
  *(word *)(VIDEO + y * 160 + x * 2) = ch | (fill_color << 8);
  x++;
  if (x >= WIDTH)
    newLine ();
  setVideoCursor (y, x);
}[/code] q里VIDEO表示昑֭地址也就?xB8000.通过 y * 160 + x 屏幕(x,y)坐标在显存中的位|?q里需要知?一个字W显C需要两个字?一个是ASCII?W二个是字符属性代码也是颜色代码.因此才必? y * 80 * 2 + x = y * 160 + x.那么ch | (fill_color << 8)也自然就是写入字W及(qing)属性代码用的了.每写一个字W光标位|加1,如果大于屏幕宽度WIDTH换?最后通过setVideoCursor讄新的 光标位置.完成了整个printCharq程.



sunGuoqin 2007-11-14 12:27 发表评论
]]>
þ99Ʒþþþþ| 9þ9þþƷ| þĻ˿| ޾ƷƵþþ| þþþùƷ۲ӰԺ| ޹һ˾þþƷ| Ʒþþþþþ| Ʒþþþþùţţapp| ۺϾþĻ| պƷþþþþþõӰ| 91Ʒ91þۺ| þþþùһ| ھƷþþþþþþõӰ | 97Ƶþþ| ˾þô߽av| 91ƷѾþþþþþþ| ŷպƷþ| þûƵ| ˹ھƷþþþӰԺ| ŷƷ99þ| AVþþþò| ˳AVɫۺϾþ| þþþþþƷþþþ| þù׾Ʒǿ| ޹ƷƬþ| þþþùһ| þþwww| avþþƷ| þŷ޹ۺ| պvavaŷvaþ| þþWWW˳ɾƷ| þٸ۲AVר| ŷ˾þô߽ۺ| þ91Ʒ91þû| þþƷ޾Ʒɫ| þþƷˬӰ| ˳վ999þþۺ| ޾Ʒþò| þùƷ԰| þþƷֻо99Ʒ| ҹƷþӰԺ|