Chinaunix首页 | 论坛 | 博客
  • 博客访问: 206947
  • 博文数量: 32
  • 博客积分: 1025
  • 博客等级: 少尉
  • 技术积分: 315
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-13 15:54
文章分类

全部博文(32)

文章存档

2011年(30)

2010年(2)

我的朋友

分类: C/C++

2011-04-01 00:59:53

sizeof()功能:计算数据空间的字节数
1.与 strlen()比较
      strlen()计算字符数组的字符数,以"\0"为结束判断,不计算为'\0'的数组元素。
      而 sizeof计算数据(包括数组、变量、类型、结构体等)所占内存空间,用字节数表示。
2.指针与静态数组的sizeof操作
      指 针均可看为变量类型的一种。所有指针变量的sizeof 操作结果均为4。
注意 :int *p; sizeof(p)=4;
                  但sizeof(*p)相当于sizeof(int);      
      对 于静态数组,sizeof可直接计算数组大小;
      例:int a[10];char b[]="hello";
              sizeof(a) 等于4*10=40;
              sizeof(b)等于6;
 注意 :数组做型参 时,数组名称当作指针使用!!
               void  fun(char p[])
               {sizeof(p) 等于4}    
经典问题:   
      double* (*a)[3][6];  
      cout<  a为指针
      cout<  *a为一个有3*6个指针元素的数组
      cout<  **a为数组一维的6个指针
      cout<  ***a为一维的第一个指针
       cout<  ****a为一个double变量
问题解析: a 是一个很奇怪的定义,他表示一个指向 double*[3][6] 类型数组的指针。既然是指针,所以 sizeof(a) 就是 4    
       
既然 a 是执行 double*[3][6] 类型的指针, *a 就表示一个 double*[3][6] 的多维数组类型,因此 sizeof(*a)=3*6*sizeof(double*)=72 。同样的, **a 表示一个 double*[6] 类型的数组,所以 sizeof(**a)=6*sizeof  (double*)=24  ***a 就表示其中的一个元素,也就是 double* 了,所以 sizeof(***a)=4 。至于 ****a ,就是一个 double 了,所以 sizeof(****a)=sizeof(double)=8    
3.格式的写法
   sizeof操作符,对变量或对象可以不加括号,但若是 类型,须加括号。
4
 .使用sizeof时string的注意事项
   string s="hello";
   sizeof(s)等于string类的大小,sizeof(s.c_str())得到的是与字符串长度。
5.union 与struct的空间计算
   总体上遵循两个原则:
   (1)整体空间是 
占用空间最大的成员(的类型)所占字节数的整倍数
   (2)数据对齐原则----内存按结构成员的先后顺序排列,当排到该成员变量时,其前面已摆放的空间大小必须是该成员类型大小的整倍数,如果不够则补齐, 以此向后类推。。。。。
   注意:数组按照单个变量一个一个的摆放,而不是看成整体。如果成员中有自定义的类、结构体,也要注意数组问题。
例: [ 引用其他帖子的内容]
因为对齐问题使结构体的 sizeof 变得比较复杂,看下面的例子: ( 默认对齐方式下 ) 

struct s1 
{ 
char a; 
double b; 
int c; 
char d; 
}; 

struct s2 
{ 
char a; 
char b; 
int c; 
double d; 
}; 

cout< 
cout< 

  
同样是两个 char 类型,一个 int 类型,一个 double 类型,但是因为对齐 问题, 导致他们的大小不同。计算结构体大小可以采用元素摆放法,我举例子说明一下:首先, CPU 判断结构体的对界,根据上一节的结论, s1  s2 的对界都取最大的元素类型,也就 是 double 类型的对界 8 。然后开始摆放每个元素。 
  
对于 s1 ,首先把 a 放到 8 的对界,假定是 0 ,此时下一个空闲的地址是 1 ,但是下一个元素 d  double 类型,要放到 8 的对界上,离 1 最接近的地址是 8 了,所以 d 被放在了 8 ,此时下一个空闲地址变成了 16 ,下一个元素 c 的对界是 4  16 可以满足,所以 c 放在了 16 ,此时下一个空闲地址变成了20 ,下一个元素 d 需要对界 1 ,也正好落在对界上,所以 d 放在了 20 ,结构体在地址 21 处结束。由于 s1 的大小需要是 8 的倍数,所以 21-23 的空间被保留, s1 的大小变成了 24  
  
对于 s2 ,首先把 a 放到 8 的对界,假定是 0 ,此时下一个空闲地址是 1 ,下一个元素的对界也是 1 ,所以 b 摆放在 1 ,下一个空闲地址变成了 2 ;下一个元素 c 的对界是 4 ,所以取离 2 最近的地址 4 摆放 c ,下一个空闲地址变成了 8 ,下一个元素 d 的对界是 8 ,所以 d 摆放在 8 ,所有元素摆放完毕,结构体在 15 处结束,占用总空间为 16 ,正好是 8 的倍数。 

  
这里有个陷阱,对于结构体 中的结构体成员,不要认为它的对齐方式就是他的大小,看下面的例子: 
struct s1 
{ 
char a[8]; 
}; 

struct s2 
{ 
double d; 
}; 

struct s3 
{ 
s1 s; 
char a; 
}; 

struct s4 
{ 
s2 s; 
char a; 
}; 
cout< 
cout< 
cout< 
cout< 
  s1 
 s2 大小虽然都是 8 ,但是 s1 的对齐方式是 1  s2  8  double ),所以在 s3  s4 中才有这样的差异。 
  
所以,在自己定义结构体的时 候,如果空间紧张的话,最好考虑对齐因素来排列结构体里的元素。
 
补充: 不要让double干扰你的位域 
  在结构体和类中,可以使用位域 来规定某个成员所能占用的空间,所以使用位域能在一定程度上节省结构体占用的空间。不过考虑下面的代码: 

struct s1 

 int i: 8; 
 int j: 4; 
 double b; 
 int a:3; 
}; 

struct s2 

 int i; 
 int j; 
 double b; 
 int a; 
}; 

struct s3 

 int i; 
 int j; 
 int a; 
 double b; 
}; 

struct s4 

 int i: 8; 
 int j: 4; 
 int a:3; 
 double b; 
}; 

cout<cout<cout<cout<  可以看到,有double存在会干涉到位域(sizeof的算法参考上一节),所以使用位域的的时候,最好把float类型和 double类型放在程序的开始或者最后。
 
相关常数:  
sizeof int:4
sizeof short:2
sizeof long:4
sizeof float:4
sizeof double:8
sizeof char:1
sizeof p:4
sizeof WORD:2
sizeof DWORD:4


==================================================



   最近在论坛里总有人问关于sizeof的问题,并且本人对这个问题也一直没有得到很好的解决,索性今天对它来个较为详细的总结,同时结合strlen进 行比较,如果能对大家有点点帮助,这是我最大的欣慰了。

一、好首先看看sizeof和strlen在MSDN上的定义:

首先看一MSDN上如何对sizeof进行定义的:

sizeof Operator

sizeof expression

The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type
(including aggregate types). This keyword returns a value of type size_t.

The expression is either an identifier or a type-cast expression (a type specifier enclosed in
parentheses).

When applied to a structure type or variable, sizeof returns the actual size, which may include
padding bytes inserted for alignment. When applied to a statically dimensioned array, sizeof
returns the size of the entire array. The sizeof operator cannot return the size of dynamically
allocated arrays or external arrays.

然后再看一下对strlen是如何定义的:

strlen

Get the length of a string.

Routine Required Header:
strlen

size_t strlen( const char *string );
Parameter
string:Null-terminated string
Libraries
All versions of the C run-time libraries.

Return Value
Each of these functions returns the number of characters in string, excluding the terminal
NULL. No return value is reserved to indicate an error.

Remarks
Each of these functions returns the number of characters in string, not including the
terminating null character. wcslen is a wide-character version of strlen; the argument of
wcslen is a wide-character string. wcslen and strlen behave identically otherwise.
二、由几个例子说开去。

第一个例子:char* ss = "0123456789";
sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针
sizeof(*ss) 结果 1 ===》*ss是第一个字符

char ss[] = "0123456789";
sizeof(ss) 结果 11 ===》ss是数组,计算到\0位置,因此是10+1
sizeof(*ss) 结果 1 ===》*ss是第一个字符

char ss[100] = "0123456789";
sizeof(ss) 结果是100 ===》ss表示在内存中的大小 100×1
strlen(ss) 结果是10 ===》strlen是个函数内部实现是用一个循环计算到\0为止之前

int ss[100] = "0123456789";
sizeof(ss) 结果 400 ===》ss表示再内存中的大小 100×4
strlen(ss) 错误 ===》strlen的参数只能是char* 且必须是以''\0''结尾的

char q[]="abc";
char p[]="a\n";
sizeof(q),sizeof(p),strlen(q),strlen(p);
结果是 4 3 3 2 第二个例子:class X
{
int i;
int j;
char k;
};
X x;
cout< cout< 第三个例子:char szPath[MAX_PATH]
如果在函数内这样定义,那么sizeof(szPath)将会是MAX_PATH,但是将szPath作为虚参声明时(void fun(char szPath[MAX_PATH])),sizeof(szPath)却会是4(指针大小) 

三、sizeof深入理解。
  • 1.sizeof 操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
  • 2.sizeof 是算符,strlen是函数。
  • 3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾 的。sizeof还可以用函数做参数,比如:short f();
    printf("%d\n", sizeof(f()));
    输出的结果是sizeof(short),即2。
  • 4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。
  • 5. 大部分编译程序 在编译的时候就把sizeof计算过了 是类型或是变量的长度 这就是sizeof(x)可以用来定义数组维数的原因char str[20]="0123456789";
    int a=strlen(str); //a=10;
    int b=sizeof(str); //而b=20;
  • 6.strlen的结果要在运行的时候才能计算出来,时用来计算字符串的长度,不是类型占内存的大小。
  • 7.sizeof 后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
  • 8.当适用了于一个结构类型时或变 量, sizeof 返回实际的大小, 当适用一静态地空间数组, sizeof 归还全部数组的尺 寸。 sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸
  • 9.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址, 如:fun(char [8])
    fun(char [])
    都等价于 fun(char *) 在C++里传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小 如果想在函数内知道数组的大小, 需要这样做: 进入函数后用memcpy拷贝出来,长度由另一个形参传进去fun(unsiged char *p1, int len)
    {
    unsigned char* buf = new unsigned char[len+1]
    memcpy(buf, p1, len);
    }
    有关内容见: C++ PRIMER?
  • 10.计算结构变量的大小就必须讨论数据对齐问题。为了CPU存取的速度最快(这同CPU取 数操作有关,详细的介绍可以参考一些计算机 原理方面的书),C++在处理数据时经常把结构变量中的成员的大小按照4或8的倍数计算,这就叫数据对齐(data alignment)。这样做可能会浪费一些内存,但理论上速度快了。当然这样的设置会在读写一些别的应用程序生成的数据文件或交换数据时带来不便。MS VC++中的对齐设定,有时候sizeof得到的与实际不等。一般在VC++中加上#pragma pack(n)的设定即可.或者如果要按字节存储,而不进行数据对齐,可以在Options对话框中修改Advanced compiler页中的Data alignment为按字节对齐。
  • 11.sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小 的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。 如sizeof(max)若此时变量max定义为int max(),sizeof(char_v) 若此时char_v定义为char char_v  [MAX]且MAX未知,sizeof(void)都不是正确形式
四、结束语

sizeof使用场合。
  • 1.sizeof 操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。 例如:  void *malloc(size_t size), 
      size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。
  • 2.用它可以看看一类型的对象在内存中所占的单元字节。void * memset(void * s,int c,sizeof(s))
  • 3.在动态分配一对象时,可以让系统知道要分配多少内存。
  • 4.便于一些类型的扩充,在windows中就有很多 结构内型就有一个专用的字段是用来放该类型的字节大小。
  • 5.由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时 用sizeof来代替常量计算。
  • 6.如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。
阅读(3378) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~