|
在 C/C++ 中,sizeof() 是一个判断数据类型或者表达式长度的运算符。 1 sizeof 定义sizeof 是 C/C++ 中的一个操作符(operator),返回一个对象或者类型所占的内存字节数。
其返回值类型为 size_t ,在头文件 stddef.h 中定义为: typedef unsigned int size_t; 从sizeof 的定义可以看出:sizeof 不是一个函数,因为函数调用必须有一对括号。 #include <stdio.h>( h, {# t/ G% H$ F2 r! t" H k3 X1 G- c. F int main(void) { int num = 97;& h, N5 C- h. V9 c3 p printf("sizeof(num = 0)的值:%d\n",sizeof(num = 0)); 8 r5 ?! Y2 r. g printf("num 的值:%d\n",num); 7 S1 P- M+ i( r, Y. q+ k return 0;) `# Q7 m0 a: L5 `% _ c: @2 i }
说明:sizeof 不是标准意义上的一元操作符,不支持链式表达式,sizeof 作用域范围内的语句不会编译成机器码,如 sizeof(num++) 中的 ++ 不执行。sizeof 也不是函数, sizeof 更像一个特殊的宏,在编译阶段求值。 2 sizeof 用法sizeof 有两种语法形式,如下: sizeof(type_name); //sizeof(类型);sizeof (object); //或sizeof object 都属于 sizeof对象; 所以: int i;% T( ?: G* d/ U3 G. bsizeof(i); //合理& l* C' ^5 F+ j: b( A; @ sizeof i; //合理 @4 f( h4 g! A0 e, X. w; N sizeof(int); //合理& z. o# S, {5 I8 q sizeof int; //不合理2 k% m1 L% A+ s+ a0 A
这里的基本数据类型是指short、int、long、float、double这样的简单内置数据类型。 由于它们的内存大小是和系统相关的,所以在不同的系统下取值可能不同。 #include <iostream>& E3 R2 b$ t0 F0 s% jusing namespace std; int main() {2 O4 H1 O9 ^8 @( c cout << "Size of char : " << sizeof(char) << endl;( X) u* T' r" t) B cout << "Size of int : " << sizeof(int) << endl;6 u% b, u+ N+ g& y cout << "Size of short int : " << sizeof(short int) << endl; n$ _9 Q$ `/ R5 q0 \/ P$ W4 s cout << "Size of long int : " << sizeof(long int) << endl; cout << "Size of float : " << sizeof(float) << endl; cout << "Size of double : " << sizeof(double) << endl;! |8 p& D* R& b; { cout << "Size of wchar_t : " << sizeof(wchar_t) << endl; return 0;/ N+ a; U; t, R% f E } 在 32 位系统下内置数据类型与其 sizeof 运算结果如下: Size of char : 1% Z! {% |+ F* g2 uSize of int : 4 Size of short int : 2" e3 l2 C6 _7 e) I1 ^' a Size of long int : 4( }8 ^; y& g" { Size of float : 4 B) }1 D" d5 U% i Size of double : 8$ F: E* ]% z6 N+ {2 e$ Q; a9 p1 v Size of wchar_t : 4
指针主要用于存储地址,前几天文章C语言指针详解提到过,指针变量的位宽等于机器字长,机器字长由 CPU 寄存器位数决定。在 32 位系统中,一个指针变量的返回值为 4 字节, 64 位系统中指针变量的 sizeof 结果为 8 字节。 char *p =”hello”; ( T R) h3 s2 msizeof( p ); // 结果为4 & E4 t/ q2 I$ }& [6 [ sizeof(*p); // 结果为1 int *pi; sizeof( pi ); //结果为4 - ?8 ^; A# Q; O" N$ @ \( O' B/ Y sizeof(*pi); //结果为4 . [! v7 M! A! i7 F, K8 @& v. \' | char **pp = &p; sizeof( pp ); // 结果为4 sizeof( *pp ); // 结果为4 1 w# Q% A+ p9 ^: H
函数类型以其返回类型作为自身类型,进行 sizeof 取值。 void fun1()) k6 \* c* i7 T5 D! [9 D{7 B3 b4 Q% z/ p3 @* l; d }6 z% f' A" X. k8 ?; O- z int fun2()* V! ?/ E% l$ t; q { return 0;4 A* ^: U# a% q } double fun3() { return 0.0;) Y6 R+ k. y2 M, N$ ^9 R! X } cout << sizeof(fun1()) << endl; //错误!无法对void类型使用sizeof- W+ Y+ w& ]5 q# T6 a5 E cout << sizeof(fun2()) << endl; //fun2()返回值类型为int,输出4 cout << sizeof(fun3()) << endl; //fun3()返回值类型为double,输出8
当 sizeof 作用于数组时,求取的是数组所有元素所占用的大小。 int A[3][5];char c[]="abcdef"; double*(*d)[3][6]; ' c5 u7 T+ Q) ?) Z, X cout<<sizeof(A)<<endl; //输出60 cout<<sizeof(A[4])<<endl; //输出20/ S7 E) t3 v3 Z2 u3 c& t# m6 f cout<<sizeof(A[0][0])<<endl;//输出4 cout<<sizeof(c)<<endl; //输出7 cout<<sizeof(d)<<endl; //输出4, U @8 m2 ^' S& w0 ~ cout<<sizeof(*d)<<endl; //输出72- y( S' ^$ }2 _& t5 r cout<<sizeof(**d)<<endl; //输出24 cout<<sizeof(***d)<<endl; //输出47 @3 D, u5 n g& [ 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)==60sizeof(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[])% Y0 w8 j& l% f2 b7 o- E{! O8 P8 d: s$ g; L) ~: b return sizeof(str);; x) i9 A# \- P, b3 S4 l( ? } int main() ^3 g4 k1 l6 d7 F4 Q3 S% u {1 x4 ^6 Q5 x, k$ Q( [ char szStr[] = "abcdef";. J9 y5 k% J6 b5 b7 s' H cout<< GetStrLength() << endl; ?3 F( J1 r2 D, Y. M: Y8 r7 \4 f2 A return 0;' o" @ z$ s/ P3 M- q }% F2 N$ @$ A, P/ t+ F6 i, s9 l5 @ 输出不是 7 ,这里函数参数 str[] 已不再是数组类型,而是蜕变成指针,我们调用函数 GetStrLength() 时,程序会在栈上分配一个大小为 7 的数组吗?不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以 str 自然为指针类型 (char*) ,输出值为:4 。
对于 struct 数据结构由 CPU 的对齐问题导致 struct 的大小变得比较复杂。具体可以查看以前的文章一文轻松理解内存对齐。 理论上,int 占 4byte , char 占一个 byte ,那么将它们放到一个结构体中应该占 4+1=5byte ;但是实际上,通过运行程序得到的结果是 8byte 。 #include<stdio.h>5 v8 B$ {5 ~8 o \0 T6 X. [struct{: Q/ d+ h8 \3 @, y4 Z int x;. a7 _/ \* c) v: _; R+ O+ x2 l: J; m- @( n char y; }Test; int main() { printf("%d\n",sizeof(Test)); // 输出8不是59 f+ c0 o' @# }. K& K; h5 U" H return 0;! w5 G% k$ {2 p6 }% r* b5 f } 结构体的大小跟结构体成员对齐有密切关系,而并非简单地等于各个成员的大小之和!比如对如下结构体两个结构体 A、B 使用 sizeof 的结果分别是:16,24。可以看出 sizeof(B) 并不等于 sizeof(int)+sizeof(double)+sizeof(int)=16 。 struct A' }. U6 E# i7 S{ int num1;+ E4 J4 j) L6 A+ J: K int num2;6 T3 _, S; |3 R$ Q& g9 R+ k double num3;8 u; V( D9 }; E };$ }: f* `1 z$ s M# x; b* U struct B { int num1;! L% _# n6 a9 [3 S7 h$ ] 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; e/ h/ B A7 j2 K+ F5 N
在这种情况下,只需要考虑对齐方式即可。 class A{ public: ) \9 L* ~$ j- Z$ F) D3 D int b; float c; ~# \& g5 S [3 z- b% f- d char d; 6 N: t' T5 C# v% L( u };$ S( v! _* {5 J. c7 p class B { }; int main(void) 2 v1 g5 e' {" ` g/ W- u5 w! C { cout << “sizeof(A) is ” << sizeof(A) << endl; //输出结果为12: X6 g9 D. g4 L; p1 g cout << “sizeof(B) is ” << sizeof(B) << endl; 3 Y0 W& A7 f8 ^+ s5 U //输出结果为1. N$ S5 w* R1 |& c9 v* J8 Z return 0 ; : f) f: ?' S/ q P4 y: s5 v( J }
{ + f b0 k6 d5 L8 ~! n1 l public: static int a; 9 N4 S3 R. ^6 [! o; \9 _5 d; g int b; float c; char d; }; int main() { A object; cout << “sizeof(object) is ” << sizeof(object) << endl; //输出结果为12 return 0 ; 3 E1 [. L! o; l$ n5 g" y, r- a* G5 ` }: b$ h; g5 i i+ |8 }' P 因为在程序编译期间,就已经为 static 变量在静态存储区域分配了内存空间,并且这块内存在程序的整个运行期间都存在。而每次声明了类 A 的一个对象的时候,为该对象在堆上,根据对象的大小分配内存。
{ public: ; a1 d1 H9 ^% I: [. A& @; E$ M static int a; " c" I2 e" i. w, W int b; % _9 L- n" U- J+ U' c& D. G# ] float c; + b1 P- u" V- o char d; int add(int x,int y) { return x+y; . ^. \2 ?6 l& j( {/ k6 W" { } 0 h% `1 l8 n/ _2 Q e" E, c& r$ I }; 0 ]) u0 l( Q- P n+ B* a int main() { A object; cout << “sizeof(object) is ” << sizeof(object) << endl; 3 i) j6 ~% {' x2 @ b = object.add(3,4); cout << “sizeof(object) is ” << sizeof(object) << endl; * z7 V3 C9 C# F" X% O4 @9 c //输出结果为12 return 0 ; / R( i" J9 R* v } 因为只有非静态类成员变量在新生成一个object的时候才需要自己的副本。所以每个非静态成员变量在生成新object需要内存,而function是不需要的。 3 sizeof 与 strlen 区别
sizeof(ss)=80, //ss表示在内存中的大小,20*4。% A- d/ Q! o4 v. D/ |' }1 ?4 M strlen(ss) //错误,strlen的参数只能是char*,且必须是以“\0”结尾的。 char *ss="0123456789"; sizeof(ss)=4, //ss是指向字符串常量的字符指针。' V8 p$ r2 u* I5 G+ l) n [ sizeof(*ss)=1, // *ss是第一个字符。2 A" o0 D: l# {( t) A |
微信公众号
手机版