1. sizeof的概念:
sizeof是C的一种单目运算符,它以字节形式给出了它的操作数的存储大小。操作数可以是一个表达式或者括起来的数据类型。操作数的存储大小由操作数的类型决定。
2. sizeof的使用方法:
sizeof用于变量可以不带括号,也可以带括号,但是用于类型必须带括号;sizeof不能用于函数类型,不完全类型和位字段。不完全类型是指具有位置存储大小的类型,如未知大小的数组类型,未知内容的结构或联合,void类型等。
3. sizeof和strlen的比较:
1) sizeof是运算符,strlen是函数
2) sizeof操作符的结果类型是size_t
3) sizeof可以用类型做参数,而strlen只能用char *做参数,而且必须以'\0'结尾。
4) 数组做sizeof的参数不退化,而做strlen的参数就退化为指针。( C的一个特性:将数组作为参数传递给函数时,数组符合自动退化为指向该数组的指针。注意sizeof是运算符,而不是函数)
5) 大多数编译程序在编译时就已经将sizeof计算出来了,这也是为什么可以使用sizeof(x)定义数组大小的原因。
6) strlen的结果要在运行时才能计算出来。它是用来计算字符串长度的,而不是用来计算类型占内存的大小。
4. 经典问题:
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变量
5. 下面的程序输出:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
struct{
short a1;
short a2;
short a3;
}A;
struct{
long a1;
short a2;
}B;
int main()
{
char* ss1 = "0123456789";
char ss2[] = "0123456789";
char ss3[100] = "0123456789";
int ss4[100];
char q1[] = "abc";
char q2[] = "a\n";
char* q3 = "a\n";
char * str1 = (char*)malloc(100);
void * str2 = (void*)malloc(100);
cout<<sizeof(ss1)<<endl;//4 指针大小固定
cout<<sizeof(ss2)<<endl;//11 10字节加上隐含的'\0'
cout<<sizeof(ss3)<<endl;//100 预分配
cout<<sizeof(ss4)<<endl;//400 预分配,但int占4字节
cout<<sizeof(q1)<<endl;//4 3+1('\0')
cout<<sizeof(q2)<<endl;//3 2+1
cout<<sizeof(q3)<<endl;//4 指针大小固定
cout<<sizeof(A)<<endl;//6 2*3
cout<<sizeof(B)<<endl;//8 4+2扩展到8(32位机的long为4byte)
cout<<sizeof(str1)<<endl;//4 指针大小固定
cout<<sizeof(str2)<<endl;//4 。。。。。
return 0;
}
结构体的大小问题(数据对齐):
在默认情况下,为了方便结构体内的元素的访问和管理,当结构体内的元素的长度都小于处理器的位数的时候,以便结构体里面最长的数据元素为对其单位,也就是说,结构体的长度一定是最长的数据元素的整数倍。如果结构体内存在长度大于处理器位数的元素,那么就以处理器的位数为对其单位。但是结构体内类型相同的连续元素将在连续的空间内,和数组一样。
结构体默认的字节对齐一般满足三个原则:
1)结构体变量的首地址能够被其最宽基本类型成员变量的大小所整除;
2)结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如果有需要编译器会在成员之间加上填充字节;
3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如果有需要编译器会在最末一个成员之后加上填充字节。