在介绍sizeof之前,先明确一点:sizeof是操作符,不是函数!
对sizeof的学习与理解主要参考MSDN上的介绍,也参考了一些其他博客或论坛中的解说。
1、sizeof的介绍:
sizeof的语法是
sizeof unary-expression sizeof ( type-name )
MSDN中说sizeof运算符的结果是size_t类型,是包含文件 STDDEF.H 中定义的整数类型。不过我没在stddef.h中找到size_t的定义,但是从stddef.h包含的头文件crtdefs.h中找到了它的定义(我使用的编译器是VS2013中的VC的编译器):
#ifndef _SIZE_T_DEFINED
#ifdef _WIN64
typedef unsigned __int64 size_t;
#else /* _WIN64 */
typedef _W64 unsigned int size_t;
#endif /* _WIN64 */
#define _SIZE_T_DEFINED
#endif /* _SIZE_T_DEFINED */
关于size_t详细信息不在这里说明。
2、sizeof的使用:
(1)操作数是类型名称
sizeof(类型名称);
输入以下代码:
printf("%lu,%lu,%lu\n",sizeof(char),sizeof(char*),sizeof(char[5]));
输出结果是:
1,8,5
可知,第一个得到的是类型所用字节数,第二个得到的是指针所占字节数,第三个得到的是数组所占字节数。
补充:
以上结果是32位系统的情况;如果是64位系统,得到的结果可能会不同。
(2)操作数是表达式
sizeof(表达式);
或
sizeof 表达式;
输入以下代码:
char arr[] = "i am a student!";
printf("%lu,%lu,%lu,%lu,%lu,%lu\n" \
,sizeof arr, sizeof *arr, sizeof &arr[0], \
sizeof(arr), sizeof(*arr), sizeof(&arr[0]));
输出的结果是:
16,1,8,16,1,8
可知,是否使用括号,表示的结果是相同的。第一个得到的是数组所占用的总字节数,第二个得到的是数组中的第一个元素所占用的字节数;第三个是指针所占字节数。(3)操作数是类或结构体
以结构体为例,输入以下代码:
struct test{
int i; //sizeof(i) = 4
int arr[3]; //sizeof(arr) = 12;
char c; //sizeof(c) = 1;
char *str; //sizeof(str) = 8;
};
int main(void) {
struct test tt[10];
printf("%lu,%lu,%lu,%lu\n", \
sizeof(tt[0].i), sizeof(tt[0].arr), \
sizeof(tt[0].c), sizeof(tt[0].str));
printf("%lu,%lu,%lu,%lu\n", \
sizeof(struct test), sizeof tt[0], \
sizeof tt, sizeof *tt);
return 0;
}
输出的结果是:
4,12,1,8
32,32,320,32
表面上看,一个结构体test所占据的空间应该为4+12+1+8=25,但实际上test被分配的空间是32。其原因与结构体分配内存空间时的对齐原则有关。具体细节见《C语言中结构体的对齐规则》。
类的情况与结构体的类似。
3、通过宏实现sizeof的定义
关于这点方法,是从帖子“谁知道sizeof这个关键字的源码实现在哪个地方可以找到?”中得到的启发。
输入以下代码:
#define sizeof1(type) ((char*)((type*)0+1)-(char*)0)
#define sizeof2(var) ((char*)(&var+1)-(char*)&var)
int main(void) {
int i;
char c;
double d;
printf("%lu, %lu.\n",sizeof1(char), sizeof2(c));
printf("%lu, %lu.\n",sizeof1(int), sizeof2(i));
printf("%lu, %lu.\n",sizeof1(double), sizeof2(d));
return 0;
}
输出的结果是:
1, 1.
4, 4.
8, 8.
表示定义没有问题。注意事项
因为sizeof操作符在编译过程中就确定了,所以有一些注意事项。
(1)关于sizeof(i++)
sizeof在编译的时候取得是i这个变量的类型所占的空间,因为在编译的时候就被i的字节数代替了,所以不会再进行自加操作。
(2)运算符永远不会产生0
当类为空或指向空指针时,输入以下代码:
class Test1{
};
class Test2{
int i;
char c;
double d;
};
int main() {
Test1 *t1 = NULL, *pt1 = new Test1;
Test2 *t2 = NULL, *pt2 = new Test2;
cout << sizeof(*t1) << ", " << sizeof(*pt1) << "\n";
cout << sizeof(*t2) << ", " << sizeof(*pt2) << "\n";
return 0;
}
输出结果为:
1, 1
16, 16
(3)运算符不能用于的操作数
- 函数(但sizeof可以应用于指向函数的指针)
- 位域
- 未定义的类
- void类型
- 动态分配的数组
- 外部数组
- 不完整类型
- 带括号的不完整类型的名称
总之sizeof适用的操作数是能够在编译步骤中确定下来的数,是静态的。
(4)数组中的元素数量
直接上代码:
#define GetLen(arr) sizeof(arr)/sizeof(arr[0])
int main() {
char str[] = "This is a string.";
cout << "The length of str is: " << GetLen(str) << endl;
return 0;
}
输出结果是:
The length of str is: 18