
在 C/C++ 中,sizeof() 是一个判断数据类型或者表达式长度的运算符。: e! z& E, ?9 ?1 b. l/ q' f0 n sizeof 是 C/C++ 中的一个操作符(operator),返回一个对象或者类型所占的内存字节数。
其返回值类型为 size_t ,在头文件 stddef.h 中定义为: typedef unsigned int size_t; 从sizeof 的定义可以看出:sizeof 不是一个函数,因为函数调用必须有一对括号。 #include <stdio.h>( f- ]( v g# ?% Y4 K6 G5 ^int main(void) { int num = 97; printf("sizeof(num = 0)的值:%d\n",sizeof(num = 0)); " I$ N" N; d- p. F, y printf("num 的值:%d\n",num); % ?( p& T. g& k$ I) ?. a return 0;" F6 j- m0 ^, B% S# V- U' i }; ]% j5 r+ q& C6 X ![]() 说明:sizeof 不是标准意义上的一元操作符,不支持链式表达式,sizeof 作用域范围内的语句不会编译成机器码,如 sizeof(num++) 中的 ++ 不执行。sizeof 也不是函数, sizeof 更像一个特殊的宏,在编译阶段求值。 2 sizeof 用法sizeof 有两种语法形式,如下: sizeof(type_name); //sizeof(类型);sizeof (object); //或sizeof object 都属于 sizeof对象;, N# w/ z( \* L" G! I% V: k3 g 所以: int i;sizeof(i); //合理 sizeof i; //合理- ~- y0 M5 \0 N+ Q$ v. } c$ \3 m, R sizeof(int); //合理 sizeof int; //不合理' B7 U' K( m8 Z4 ]
这里的基本数据类型是指short、int、long、float、double这样的简单内置数据类型。 由于它们的内存大小是和系统相关的,所以在不同的系统下取值可能不同。 #include <iostream>using namespace std; : }$ P/ [* q* e1 j int main() {. K' j/ y2 m# g7 t/ _- v! r cout << "Size of char : " << sizeof(char) << endl; cout << "Size of int : " << sizeof(int) << endl; _. H( W ]& }; O( u cout << "Size of short int : " << sizeof(short int) << endl;# t* ?8 f- v! c; B+ A" A5 L cout << "Size of long int : " << sizeof(long int) << endl;$ B* b- ]4 Z% ~ K cout << "Size of float : " << sizeof(float) << endl; cout << "Size of double : " << sizeof(double) << endl; cout << "Size of wchar_t : " << sizeof(wchar_t) << endl;1 @4 q4 L( ~* ?& H1 w6 G return 0; } 在 32 位系统下内置数据类型与其 sizeof 运算结果如下: Size of char : 1) b% z$ P ]/ j, ?: wSize of int : 4# E( ~" p+ P( l* V! h Size of short int : 22 z4 [% [" _, \9 c) I$ A$ L Size of long int : 48 n' k- Y8 u/ n4 |9 {6 C Size of float : 40 x! `. f$ Z, B; Q* e Size of double : 8' b |& c! ~: H% t Size of wchar_t : 4! Z4 [1 U$ Q x4 D2 ~1 S
指针主要用于存储地址,前几天文章C语言指针详解提到过,指针变量的位宽等于机器字长,机器字长由 CPU 寄存器位数决定。在 32 位系统中,一个指针变量的返回值为 4 字节, 64 位系统中指针变量的 sizeof 结果为 8 字节。 char *p =”hello”; # w2 {' ^& `4 H+ zsizeof( p ); // 结果为4 sizeof(*p); // 结果为1 int *pi; 5 U/ ^; j" a5 _ d/ z sizeof( pi ); //结果为4 sizeof(*pi); //结果为4 char **pp = &p; sizeof( pp ); // 结果为4 , @/ `. V, H& d0 z" h7 m. k sizeof( *pp ); // 结果为4 9 J6 i; Z ^1 ]
函数类型以其返回类型作为自身类型,进行 sizeof 取值。 void fun1()) T8 f4 G7 n4 h- w' c{. f% ~% r# Q# e3 ~5 [ }4 O0 u! _& [' M* Z int fun2(), x8 k2 B/ L) I& U( @% U {7 s* F7 \* V- K# C return 0;7 u8 {: h9 t2 G& U7 ~) c } double fun3() { return 0.0;8 p3 c1 ?( M8 _# O/ m1 v } cout << sizeof(fun1()) << endl; //错误!无法对void类型使用sizeof& b& h5 K( Q, J/ E cout << sizeof(fun2()) << endl; //fun2()返回值类型为int,输出4' [$ K9 b7 l3 d/ u cout << sizeof(fun3()) << endl; //fun3()返回值类型为double,输出8
当 sizeof 作用于数组时,求取的是数组所有元素所占用的大小。 int A[3][5];* i6 d4 `2 L, n" S, P* \ \: S: n9 z2 jchar c[]="abcdef"; double*(*d)[3][6];2 F; Z n, S2 x) P" v& P 7 p' v# _1 O+ M/ B7 d2 y& A+ R cout<<sizeof(A)<<endl; //输出60 cout<<sizeof(A[4])<<endl; //输出20 cout<<sizeof(A[0][0])<<endl;//输出4 cout<<sizeof(c)<<endl; //输出7' b) G8 x7 M' w" ?3 \- f0 ]; O# n cout<<sizeof(d)<<endl; //输出4 cout<<sizeof(*d)<<endl; //输出720 j, @9 K3 P! K cout<<sizeof(**d)<<endl; //输出24 cout<<sizeof(***d)<<endl; //输出4 cout<<sizeof(****d)<<endl; //输出8. F4 u% p. r7 ~+ }& a A 的数据类型是 int[3][5] ,A[4] 的数据类型是 int[5],A[0][0]数据类型是int 。所以: sizeof(A)==sizeof(int[3][5])==3*5*sizeof(int)==608 f' T2 Z1 \( S+ y: R( Psizeof(A[4])==sizeof(int[5])=5*sizeof(int)==206 {1 @7 R( Z+ V" x6 V# ~ 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);* ~- P& C& I* [( s- { }: U) e0 o! M v2 {* t - _4 ^: k8 l9 c int main()/ c$ O, O( h# Z$ e { char szStr[] = "abcdef";& @/ P9 |& v9 j9 E8 l# ?5 ~* J' b. K& u cout<< GetStrLength() << endl; return 0; }* z( o" Y4 K- h1 \0 P 输出不是 7 ,这里函数参数 str[] 已不再是数组类型,而是蜕变成指针,我们调用函数 GetStrLength() 时,程序会在栈上分配一个大小为 7 的数组吗?不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以 str 自然为指针类型 (char*) ,输出值为:4 。
对于 struct 数据结构由 CPU 的对齐问题导致 struct 的大小变得比较复杂。具体可以查看以前的文章一文轻松理解内存对齐。 理论上,int 占 4byte , char 占一个 byte ,那么将它们放到一个结构体中应该占 4+1=5byte ;但是实际上,通过运行程序得到的结果是 8byte 。 #include<stdio.h>* o* `! a+ Y% V% Mstruct{ int x;$ p2 q5 `3 q3 _' [ char y;) G3 T1 ]9 O! T& t ^% u }Test; int main()8 m5 P5 j& U" A: A {( b0 ~. w0 H7 j( ?& u. t8 ]/ n$ y printf("%d\n",sizeof(Test)); // 输出8不是5 return 0;4 ]# |0 I" e" l+ S& q8 C } 结构体的大小跟结构体成员对齐有密切关系,而并非简单地等于各个成员的大小之和!比如对如下结构体两个结构体 A、B 使用 sizeof 的结果分别是:16,24。可以看出 sizeof(B) 并不等于 sizeof(int)+sizeof(double)+sizeof(int)=16 。 struct A{ int num1;$ A0 m1 Y; ~6 o' I3 C) G+ v int num2; double num3; }; struct B1 R( N9 L( L* m( }& ]3 {2 H { int num1; double num3;0 l6 n; J3 \ D/ }% V 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
在这种情况下,只需要考虑对齐方式即可。 class A{ 4 }% t3 L: {: b/ W' A d6 U public: : L( |! ?# n& c! z int b; # s4 Z/ w6 |) Z, I9 B( P* u3 U float c; char d; 6 @6 g9 G* p0 i# O }; class B { 5 c# `$ j# @0 [ H) C, Y };/ k0 H/ J' a) V7 b int main(void) & t' R: [+ y* F" i C, [- T% ]( L { cout << “sizeof(A) is ” << sizeof(A) << endl; & b& W. Y) b( o8 x7 [ //输出结果为129 q; Z4 D0 v3 u* W8 K+ ~& e, C$ v cout << “sizeof(B) is ” << sizeof(B) << endl; //输出结果为1 return 0 ; 0 O7 h8 j* O8 ?$ |* w }
{ ' f9 E, f7 Z6 o5 ^# H3 I# S/ S; b public: " v8 ]4 C8 @' u# L; ? static int a; % l% I" N% R! v( G+ ^ int b; : Q3 L2 w! R4 t6 H float c; ' ~. B- l4 P* o7 ] p char d; };- a% [5 S5 ?/ C- S5 d' c! j' S & R' T5 W4 z0 f, M' u7 W. J: r int main() { 1 P# a% f, t# H6 R' F6 M A object; cout << “sizeof(object) is ” << sizeof(object) << endl; //输出结果为126 [: e2 M4 R2 x& {' F' r return 0 ; f; N4 l; N( o/ L' i; t( u A/ n. V& J }5 @0 |: \! G& D% |8 M0 P$ } 因为在程序编译期间,就已经为 static 变量在静态存储区域分配了内存空间,并且这块内存在程序的整个运行期间都存在。而每次声明了类 A 的一个对象的时候,为该对象在堆上,根据对象的大小分配内存。
{ public: static int a; 7 e7 y; z# o0 T int b; float c; " Y. B8 A, |) `4 H1 m3 t+ C char d; int add(int x,int y) { & w* i+ A+ k* M7 b# m return x+y; 2 T" e+ C1 _0 U3 s# L. z6 c } / R6 ]! |4 j5 y N; K; C }; int main() { A object; " n5 Q. L) P0 }8 `9 ~6 o cout << “sizeof(object) is ” << sizeof(object) << endl; b = object.add(3,4); 8 ?" U0 w2 k2 T9 ^ cout << “sizeof(object) is ” << sizeof(object) << endl; - W0 @, z. a6 n //输出结果为12 return 0 ; }' L& O1 j2 ?2 }7 R. Y: u 因为只有非静态类成员变量在新生成一个object的时候才需要自己的副本。所以每个非静态成员变量在生成新object需要内存,而function是不需要的。 3 sizeof 与 strlen 区别
sizeof(ss)=80, //ss表示在内存中的大小,20*4。 strlen(ss) //错误,strlen的参数只能是char*,且必须是以“\0”结尾的。! E0 h* M- k1 ~0 ^# | char *ss="0123456789";5 N$ f$ W) d% l+ m) |6 [6 g' } sizeof(ss)=4, //ss是指向字符串常量的字符指针。# Y- y! F8 B, V$ _. }; o# G sizeof(*ss)=1, // *ss是第一个字符。 |