在 C/C++
中,sizeof()
是一个判断数据类型或者表达式长度的运算符。
sizeof
定义sizeof
是 C/C++
中的一个操作符(operator),返回一个对象或者类型所占的内存字节数。
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.? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ?——来自MSDN
其返回值类型为 size_t
,在头文件 stddef.h
中定义为: typedef unsigned int size_t
;
从sizeof
的定义可以看出:sizeof
不是一个函数,因为函数调用必须有一对括号。
#include?<stdio.h>
int?main(void)
{
???int?num?=?97;
???printf("sizeof(num?=?0)的值:%d\n",sizeof(num?=?0));???
???printf("num?的值:%d\n",num);???
???return?0;
}
运行结果为4,97;并不是4,0
说明:sizeof
不是标准意义上的一元操作符,不支持链式表达式,sizeof
作用域范围内的语句不会编译成机器码,如sizeof(num++)
中的 ++
不执行。sizeof
也不是函数, sizeof
更像一个特殊的宏,在编译阶段求值。
sizeof
用法sizeof
有两种语法形式,如下:
sizeof(type_name);????//sizeof(类型);
sizeof?(object);??????//或sizeof?object?都属于?sizeof对象;
所以:
int?i;
sizeof(i);????//合理
sizeof?i;?????//合理
sizeof(int);??//合理
sizeof?int;???//不合理
sizeof
时,sizeof type_name
是非法的,必须写为 sizeof(type_name)
;sizeof ()
这种形式都是对的;sizeof
这里的基本数据类型是指short、int、long、float、double
这样的简单内置数据类型。
由于它们的内存大小是和系统相关的,所以在不同的系统下取值可能不同。
#include?<iostream>
using?namespace?std;
?
int?main()
{
???cout?<<?"Size?of?char?:?"?<<?sizeof(char)?<<?endl;
???cout?<<?"Size?of?int?:?"?<<?sizeof(int)?<<?endl;
???cout?<<?"Size?of?short?int?:?"?<<?sizeof(short?int)?<<?endl;
???cout?<<?"Size?of?long?int?:?"?<<?sizeof(long?int)?<<?endl;
???cout?<<?"Size?of?float?:?"?<<?sizeof(float)?<<?endl;
???cout?<<?"Size?of?double?:?"?<<?sizeof(double)?<<?endl;
???cout?<<?"Size?of?wchar_t?:?"?<<?sizeof(wchar_t)?<<?endl;
???return?0;
}
在 32 位系统下内置数据类型与其 sizeof
运算结果如下:
Size?of?char?:?1
Size?of?int?:?4
Size?of?short?int?:?2
Size?of?long?int?:?4
Size?of?float?:?4
Size?of?double?:?8
Size?of?wchar_t?:?4
unsigned
不影响内置类型 sizeof
的取值sizeof
指针主要用于存储地址,前几天文章C语言指针详解提到过,指针变量的位宽等于机器字长,机器字长由 CPU 寄存器位数决定。在 32 位系统中,一个指针变量的返回值为 4 字节, 64 位系统中指针变量的 sizeof
结果为 8 字节。
char?*p?=”hello”;?
sizeof(?p?);???????//?结果为4?
sizeof(*p);????????//?结果为1?
int?*pi;?
sizeof(?pi?);??????//结果为4?
sizeof(*pi);???????//结果为4?
char?**pp?=?&p;?
sizeof(?pp?);??????//?结果为4?
sizeof(?*pp?);?????//?结果为4?
sizeof
值与指针所指的对象类型没有任何关系,与指针申请多少空间没有关系,所有的指针变量所占内存大小均相等。sizeof
函数类型以其返回类型作为自身类型,进行 sizeof
取值。
void?fun1()
{
}
int?fun2()
{
???return?0;
}
double?fun3()
{
???return?0.0;
}
cout << sizeof(fun1())?<< endl;??//错误!无法对void类型使用sizeof
cout?<<?sizeof(fun2())?<<?endl;??//fun2()返回值类型为int,输出4
cout?<<?sizeof(fun3())?<<?endl;??//fun3()返回值类型为double,输出8
void
函数和函数指针进行 sizeof
取值。sizeof
当 sizeof
作用于数组时,求取的是数组所有元素所占用的大小。
????int?A[3][5];
????char?c[]="abcdef";
????double*(*d)[3][6];
????cout<<sizeof(A)<<endl;??????//输出60
????cout<<sizeof(A[4])<<endl;???//输出20
????cout<<sizeof(A[0][0])<<endl;//输出4
????cout<<sizeof(c)<<endl;??????//输出7
????cout<<sizeof(d)<<endl;??????//输出4
????cout<<sizeof(*d)<<endl;?????//输出72
????cout<<sizeof(**d)<<endl;????//输出24
????cout<<sizeof(***d)<<endl;???//输出4
????cout<<sizeof(****d)<<endl;??//输出8
A 的数据类型是 int[3][5]
,A[4]
的数据类型是 int[5],A[0][0]
数据类型是 int
。所以:
sizeof(A)==sizeof(int[3][5])==3*5*sizeof(int)==60
sizeof(A[4])==sizeof(int[5])=5*sizeof(int)==20
sizeof(A[0][0])==sizeof(int)==4
如果字符数组表示字符串,数组末自动插入 '\0',所以 c 的数据类型是 char[7]
,所以 sizeof(c)=sizeof(char[7])==7
。
d 是一个很奇怪的定义,他表示一个指向 double*[3][6]
类型数组的指针。既然是指针,所以 sizeof(d)
就是4。
既然 d 是执行 double*[3][6]
类型的指针, *d
就表示一个 double*[3][6]
的多维数组类型,因此 sizeof(*a)=3*6*sizeof(double*)=72
。
**d
表示一个 double*[6]
类型的数组,所以 sizeof(**d)=6*sizeof (double*)=24
。
***d
表示其中的一个元素,也就是 double*
,所以 sizeof(***d)=4
。
****d
是一个 double
,所以 sizeof(****d)=sizeof(double)=8
。
当数组作为函数形参时,下面输出结果应该是多少呢?
int?GetStrLength(char?str[])
{
???return?sizeof(str);
}
int?main()
{
???char?szStr[]?=?"abcdef";
???cout<<?GetStrLength()?<<?endl;
???return?0;
}
输出不是 7 ,这里函数参数 str[]
已不再是数组类型,而是蜕变成指针,我们调用函数 GetStrLength()
时,程序会在栈上分配一个大小为 7 的数组吗?不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以 str 自然为指针类型 (char*) ,输出值为:4 。
sizeof
对于 struct 数据结构由 CPU 的对齐问题导致 struct 的大小变得比较复杂。具体可以查看以前的文章一文轻松理解内存对齐。
理论上,int 占 4byte , char 占一个 byte ,那么将它们放到一个结构体中应该占 4+1=5byte ;但是实际上,通过运行程序得到的结果是 8byte 。
#include<stdio.h>
struct{
????int?x;
????char?y;
}Test;
int?main()
{
????printf("%d\n",sizeof(Test));?//?输出8不是5
????return?0;
}
结构体的大小跟结构体成员对齐有密切关系,而并非简单地等于各个成员的大小之和!比如对如下结构体两个结构体 A、B 使用 sizeof
的结果分别是:16,24。可以看出 sizeof(B)
并不等于 sizeof(int)+sizeof(double)+sizeof(int)=16
。
struct?A
{
??int?num1;
??int?num2;
??double?num3;
};
struct?B
{
??int?num1;
??double?num3;
??int?num2;
};
结构体A和B中包含的成员都一样,只不过顺序不同而已,为什么其大小不一样呢?要解释这个问题,就要了解结构体成员对齐的规则。
从三个规则我们来看看为什么 sizeof(B)
等于 24 :首先假设结构体的首地址为0,第一个成员 num1 的首地址是 0 (满足规则2),它的类型是 int ,因此它占用地址空间 0——3
。第二个成员 num3 是 double 类型,它占用 8 个字节,由于之前的 num1 只占用了 4 个字节,为了满足规则 2 ,需要使用规则 3 在 num1 后面填充 4 个字节(4——7
),使得 num3 的起始地址偏移量为 8 ,因此 num3 占用的地址空间是:8——15
。第三个成员 num2 是 int 型,其大小为 4 ,由于 num1 和num3 一共占用了 16 个字节,此时无须任何填充就能满足规则 2。因此 num2 占用的地址空间是 16——19
。那么是不是结构体的总大小就是 0——19
共 20 个字节呢?请注意,别忘了规则1!由于结构体内最大成员是 double 占用 8 个字节,因此最后还需要在 num2 后面填充 4 个字节,使得结构体总体大小为 24 。
struct?S{?};?
sizeof(S);?//?结果为1
sizeof
在这种情况下,只需要考虑对齐方式即可。
class?A?
{?
??public:?
??int?b;?
??float?c;?
??char?d;?
};
class?B
{?
};
int?main(void)?
{?
??cout?<<?“sizeof(A)?is?”?<<?sizeof(A)?<<?endl;?
??//输出结果为12
??cout?<<?“sizeof(B)?is?”?<<?sizeof(B)?<<?endl;?
??//输出结果为1
??return?0?;?
}
class?A?
{?
??public:?
??static?int?a;?
??int?b;?
??float?c;?
??char?d;?
};
int?main()?
{?
??A?object;?
??cout?<<?“sizeof(object)?is?”?<<?sizeof(object)?<<?endl;?
??//输出结果为12
??return?0?;?
}
因为在程序编译期间,就已经为 static 变量在静态存储区域分配了内存空间,并且这块内存在程序的整个运行期间都存在。而每次声明了类 A 的一个对象的时候,为该对象在堆上,根据对象的大小分配内存。
class?A?
{?
??public:?
??static?int?a;?
??int?b;?
??float?c;?
??char?d;?
??int?add(int?x,int?y)?
??{?
????return?x+y;?
??}?
};
int?main()?
{?
??A?object;?
??cout?<<?“sizeof(object)?is?”?<<?sizeof(object)?<<?endl;?
??b?=?object.add(3,4);?
??cout?<<?“sizeof(object)?is?”?<<?sizeof(object)?<<?endl;?
??//输出结果为12
??return?0?;?
}
因为只有非静态类成员变量在新生成一个object的时候才需要自己的副本。所以每个非静态成员变量在生成新object需要内存,而function是不需要的。
sizeof
与 strlen
区别sizeof
是一个操作符,strlen
是库函数。sizeof
的参数可以是数据的类型,也可以是变量,而 strlen
只能以结尾sizeof
的结果,而 strlen
函数必须在运行时才能计算出来。并且 sizeof
计算的是数据类型占内存的大小,而strlen
计算的是字符串实际的长度。sizeof
的参数不退化,传递给 strlen
就退化为指针了。如:?int?ss[20]="0123456789";
?sizeof(ss)=80, //ss表示在内存中的大小,20*4。
?strlen(ss)????//错误,strlen的参数只能是char*,且必须是以“\0”结尾的。
?char?*ss="0123456789";
?sizeof(ss)=4, ?//ss是指向字符串常量的字符指针。
?sizeof(*ss)=1, //?*ss是第一个字符。
本文系转载,前往查看
如有侵权,请联系?cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系?cloudcommunity@tencent.com 删除。