c语言详解sizeof & sizeof函数总结

一、sizeof的概念

  sizeof是C语言的一种单目操作符,如C语言的其他操作符++、--等。
它并不是函数。
sizeof操作符以字节形式给出了其操作数的存储大小。
操作数可以是一个表达式或括在括号内的类型名。
操作数的存储大小由操作数的类型决定。 

二、sizeof的使用方法

  1、用于数据类型 

  sizeof使用形式: sizeof(type)
  数据类型必须用括号括住: sizeof(int)

  2、用于变量 

  sizeof使用形式: sizeof(var_name) 或 sizeof var_name 
  变量名可以不用括号括住.如sizeof (var_name),sizeof var_name等都是正确形式
带括号的用法更普遍,大多数程序员采用这种形式。 

  注意:sizeof操作符不能用于函数类型,不完全类型或位字段。
不完全类型指具有未知存储大小的数据类型,
如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。 
  例如: sizeof(max) --
若此时变量max定义为int max();
sizeof(char_v)  --若此时char_v定义为char char_v[MAX]且MAX未知,
sizeof(void)
以上都是不正确形式。 

三、sizeof的结果(以下结果都是在Linux v2.6 gcc v4获取)

  sizeof操作符的结果类型是size_t
它在头文件中定义为: typedef unsigned int size_t;
该类型保证能容纳实现所建立的最大对象的字节大小.

  1、ANSI C正式规定字符类型为1字节。 

sizeof(char)= 1;
sizeof(unsigned char) = 1;
sizeof(signed char) = 1;
  
  2、其他类型在ANSI C中没有具体规定,大小依赖于实现。
 
sizeof(int) = 4;
sizeof(unsigned int)= 4;
sizeof(short int)= 2;
sizeof(unsigned short) = 2;
sizeof(long int)= 4;
sizeof(unsigned long)= 4;
sizeof(float)= 4;
sizeof(double)= 8;
sizeof(long double)= 12;

  3、当操作数是指针时,sizeof依赖于编译器。
Microsoft C/C++7.0中,near类指针字节数为2,far、huge类指针字节数为4。
一般Unix/Linux的指针字节数为4。 
例如: char *p; //Linux中
sizeof(p) = 4;

  4、当操作数具有数组类型时,其结果是数组的总字节数。
例如: char a[5];
int b[5];
sizeof(a) = 5;
sizeof(b) = 20;
5、当操作数是具体的字符串或者数值时,会根据具体的类型进行相应转化。
例如: sizeof(8) = 4; //自动转化为int类型
sizeof(8.8) = 8; //自动转化为double类型,注意,不是float类型
sizeof("ab") = 3 //自动转化为数组类型,
//长度是4,不是3,因为加上了最后的'\n'符
//有资料说,会自动转化为指针类型(Linux为4)
//可能和操作系统与编译器有关系

  6、当操作数是联合类型时,sizeof是其最大字节成员的字节数。
当操作数是结构类型时,sizeof是其成员类型的总字节数,包括补充字节在内。 
还是让我们拿例子来说话:
union u{ //对union来说
char c;
double d;
}u;
sizeof(u) = max(sizeof(c),sizeof(d)) = sizeof(1,8) = 8;

  struct a{ //对struct来说
char b; 
double x;
}a;
  在Linux上: sizeof(a) = 12;
而一般sizeof(char) + sizeof(double) = 9;
  这是因为编译器在考虑对齐问题时,在结构中插入空位以控制各成员对象的地址对齐。
但如果全对齐的话,sizeof(a) = 16, 这是因为b被放到偏移量为0的地址,占1个字节;
在存放x时,double类型长度为8,需要放到能被8整除的偏移量上,这时候需要补7个空字节,
达到8个,这时候偏移量为8,放上x后长度为16。
在此例中,所有的结构成员都要放在被4整除的地址(Linux的存放方式),这里补3个字节,所以为12。

  7、当操作数是函数中的数组形参或函数类型的形参:
sizeof给出其指针的大小,Linux中值为4。

四、sizeof与其他操作符的关系

  sizeof的优先级为2级,比/、%等3级运算符优先级高。
它可以与其他操作符一起组成表达式:
例如: int i = 10;
i * sizeof(int);

五、sizeof的主要用途

  1、主要用途是与存储分配和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));  






sizeof函数功能:
计算数据空间的字节数

1.与strlen()比较
strlen计算字符数组的字符数,以"\0"为结束判断,不计算为'\0'的数组元素。
sizeof计算数据(包括数组、变量、类型、结构体等)所占内存空间,用字节数表示(当然用在字符数组计算"\0"的大小)。
2.指针与静态数组的sizeof操作
指针均可看为变量类型的一种。所有指针变量的sizeof 操作结果均为4。
实例1::char *p;
sizeof(p)=4;
sizeof(*p) = 1;   //相当于sizeof(char);  
实例2:  
对于静态数组,sizeof可直接计算数组大小;
例:int a[10];
char b[]="hello";
sizeof(a)等于4*10=40;
sizeof(b)等于6;
void  fun(char p[])
{
 sizeof(p);         //等于4,数组做型参时,数组名称当作指针使用!!
}
实例3(经典考题):
double* (*a)[3][6];
cout<<sizeof(a)<<endl; // 4 a为指针
cout<<sizeof(*a)<<endl; // 72 *a为一个有3*6个指针元素的数组
cout<<sizeof(**a)<<endl; // 24 **a为数组一维的6个指针
cout<<sizeof(***a)<<endl; // 4 ***a为一维的第一个指针
cout<<sizeof(****a)<<endl; // 8 ****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类的大小(32),sizeof(s.c_str())得到的是与字符串长度(4)。
5.union 与struct的空间计算
总体上遵循两个原则:
(1)整体空间是占用空间最大的成员(类型)所占字节的整数倍
(2)数据对齐原则----数据在内存中按照结构成员先后顺序进行排序,当排到该成员变量时,其前面已摆放的空间大小必须是该成员类型大小的整倍数,如果不够则补齐,以此向后类推。。。。。
注意:数组按照单个变量一个一个的摆放,而不是看成整体。如果成员中有自定义的类、结构体,也要注意数组问题。
实例4:[引用其他帖子的内容]
因为对齐问题使结构体的sizeof变得比较复杂,看下面的例子:(默认对齐方式下)
struct s1
{
 char a;
 double b;
 int c;
 char d;
};
struct s2
{
 char a;
 char b;
 int c;
 double d;
};
cout<<sizeof(s1)<<endl; // 24
cout<<sizeof(s2)<<endl; // 16
同样是两个char类型,一个int类型,一个double类型,但是因为对齐问题,导致他们的大小不同。计算结构体大小可以采用元素摆放法,我举例子说明一下:首先,CPU判断结构体的对界,根据上一节的结论,s1和s2的对界都取最大的元素类型,也就是double类型的对界8。然后开始摆放每个元素。
对于s1,首先把a放到8的对界,假定是0,此时下一个空闲的地址是1,但是下一个元素b是double类型,要放到8的对界上,离1最接近的地址是8了,所以b被放在了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的倍数。
这里有个陷阱,对于结构体中的结构体成员,不要认为它的对齐方式就是他的大小,看下面的例子:
实例5:
struct s1
{
 char a[8];
};
struct s2
{
 double d;
};
struct s3
{
 s1 s;
 char a;
};
struct s4
{
 s2 s;
 char a;
};
cout<<sizeof(s1)<<endl; // 8
cout<<sizeof(s2)<<endl; // 8
cout<<sizeof(s3)<<endl; // 9
cout<<sizeof(s4)<<endl; // 16;
s1和s2大小虽然都是8,但是s1的对齐方式是1,s2是8(double),所以在s3和s4中才有这样的差异。
所以,在自己定义结构体的时候,如果空间紧张的话,最好考虑对齐因素来排列结构体里的元素。
   相关常数:
   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



  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值