声明:1)C中sizeof用法 <<<这篇博客分析的比较详细,我仅仅是记录一些关键点,便于自己查阅。
1)作用
sizeof操作符以字节形式
给出其操作数的存储大小。操作数可以是一个表达式 或 括在括号内的类型名。
2)用法
-
用于数据类型
sizeof(type),数据类型必须用括号括起来。 -
用于变量
sizeof(var_name),可以不用括号。注意,不能用于void。
3)注意规则
(1)常见的数据类型
char、unsigned char、signed char ==1;
short、int、unsigned int、long int、long long==2、4、4、4、8;
float、double=4、8;
(2)指针
我在本地测试,上述类型的指针sizeof都是8字节。
(3)数组u
其结果= sizeof(数据中元素类型)* 数组大小;如:int arr[10] 的结果就是 40字节。
(4) union类型
联合类型操作数的sizeof是其最大字节成员
的字节数。即所有成员中最长的。
(5)struct类型(结构体)
注意对齐问题
结构体类型操作数的sizeof是这种类型对象的总字节数,包括任何填充在内。
(6)参数为结构或类
sizeof应用在类和结构的处理情况相同,但是有两点需要注意。
- 第一,结构或类中的静态成员不对结构或类的大小产生影响,因为静态变量的存储位置于结构或类的实例地址无关;
- 第二,没有成员变量的结构或类的大小为1,因为必须保证结构或类的每一个实例在内存中都有唯一的地址。
Class Test{int a;static double c};//sizeof(Test)=4.
Test *s;//sizeof(s)=4,s为一个指针。
Class test1{ };//sizeof(test1)=1;
4)sizeof与strlen的区别
(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。
//因为f的返回类型为short,所以相当于求sizeof(short)。
(4)sizeof大部分在编译时就计算过了,所以可以用来定义数组的维数;
strlen的结果要在运行时才能计算,用来计算字符串的长度,不是类型占内存的大小。
(5)数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址。
在C++里参数传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小。如果想在函数内知道数组的大小, 需要这样做:进入函数后用memcpy拷贝出来,长度由另一个形参传进去。
5)sizeof中struct,class,union对齐分析
结构体1:
struct s{
int a;
char b;
double c;
};
结构体2:
struct s{
int a;
double c;
char b;
};
上面两个结构体,仅仅是成员的顺序不同,但是sizeof的计算结果却有区别,结构体1的结果是16,结构体2的结果是24。这是为什么呢?
这是VC对变量存储的一个特殊处理。为了提高CPU的存储速度,VC对一些变量的起始地址做了对齐处理。在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。
各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,
填充情况1:按照对齐方式调整位置,空缺的字节VC会自动填充。
填充情况2:VC为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
注意:类class
对于类而言,类的大小与下列数据有关:
- 为类的非静态成员数据的类型大小之和;
- 有编译器额外加入的成员变量的大小,用来支持语言的某些特性(如,指向虚函数的指针);
- 为了优化存取效率,进行的边缘调整;
- 与类中的构造函数,析构函数以及其他的成员函数无关。
参考:
1)C中sizeof用法