
在 C/C++ 中,sizeof() 是一个判断数据类型或者表达式长度的运算符。+ g8 c0 ^$ j. V2 h" I! e sizeof 是 C/C++ 中的一个操作符(operator),返回一个对象或者类型所占的内存字节数。
其返回值类型为 size_t ,在头文件 stddef.h 中定义为: typedef unsigned int size_t; 从sizeof 的定义可以看出:sizeof 不是一个函数,因为函数调用必须有一对括号。 #include <stdio.h>9 S% Y- [( t( I3 A) _, e) e5 N2 g, I- u+ S, Y) s# {7 [* D int main(void) {# W R! R) o% l; ?8 A8 z int num = 97;5 p7 q1 i. |) m+ i & b+ s4 R/ _3 S8 F* |1 Z! t3 }% ^0 C' I printf("sizeof(num = 0)的值:%d\n",sizeof(num = 0)); : F7 v( f5 f7 u+ A printf("num 的值:%d\n",num); return 0; n. j4 H. O# C: {8 u! N. K }. ~- t2 {0 c2 W# i' m' T ![]() 说明:sizeof 不是标准意义上的一元操作符,不支持链式表达式,sizeof 作用域范围内的语句不会编译成机器码,如 sizeof(num++) 中的 ++ 不执行。sizeof 也不是函数, sizeof 更像一个特殊的宏,在编译阶段求值。 2 sizeof 用法sizeof 有两种语法形式,如下: sizeof(type_name); //sizeof(类型);2 N) z$ f: J4 ^5 r4 l1 ]+ M( |sizeof (object); //或sizeof object 都属于 sizeof对象;7 H0 ]) k- O$ i/ \6 x5 N. r' i% P 所以: int i;sizeof(i); //合理 sizeof i; //合理 sizeof(int); //合理8 h$ {0 I i2 ?# \1 W, c5 v sizeof int; //不合理
这里的基本数据类型是指short、int、long、float、double这样的简单内置数据类型。 由于它们的内存大小是和系统相关的,所以在不同的系统下取值可能不同。 #include <iostream>using namespace std; 0 S9 ~0 @' V8 A' b int main() {7 }1 A5 `+ h' \# x5 }+ z cout << "Size of char : " << sizeof(char) << endl;3 L2 F \# r: ~1 y/ d4 ]. } cout << "Size of int : " << sizeof(int) << endl; cout << "Size of short int : " << sizeof(short int) << endl;! X0 w. k: Z* C! h cout << "Size of long int : " << sizeof(long int) << endl; cout << "Size of float : " << sizeof(float) << endl;1 V+ ~; e" H7 l1 G0 r cout << "Size of double : " << sizeof(double) << endl;- Z9 R1 \" q2 W2 q7 C cout << "Size of wchar_t : " << sizeof(wchar_t) << endl; return 0;& o: ]; e6 m7 x% Z9 z( M } 在 32 位系统下内置数据类型与其 sizeof 运算结果如下: Size of char : 1Size of int : 4. ^) ^- c+ w8 d7 @& ^ Size of short int : 2; ^4 y3 Z8 N7 T! ` Size of long int : 4 Size of float : 4 Size of double : 8 Size of wchar_t : 42 U, E1 e1 ]9 c0 c9 j1 C. ^# @- y7 j
指针主要用于存储地址,前几天文章C语言指针详解提到过,指针变量的位宽等于机器字长,机器字长由 CPU 寄存器位数决定。在 32 位系统中,一个指针变量的返回值为 4 字节, 64 位系统中指针变量的 sizeof 结果为 8 字节。 char *p =”hello”;sizeof( p ); // 结果为4 sizeof(*p); // 结果为1 int *pi; 0 z$ i T, E5 P; I+ s8 W: f) Q( Q$ d sizeof( pi ); //结果为4 sizeof(*pi); //结果为4 char **pp = &p; + h7 _0 D0 z/ o) M sizeof( pp ); // 结果为4 2 @4 I, L0 _" t0 y sizeof( *pp ); // 结果为4
函数类型以其返回类型作为自身类型,进行 sizeof 取值。 void fun1(){ }5 i3 R/ d" W4 B3 [. f6 g' ` D int fun2() { return 0; } double fun3() {7 ]$ g" A8 D# G" E O! J return 0.0; } cout << sizeof(fun1()) << endl; //错误!无法对void类型使用sizeof cout << sizeof(fun2()) << endl; //fun2()返回值类型为int,输出4, g o: h# Y- S2 ]! s cout << sizeof(fun3()) << endl; //fun3()返回值类型为double,输出8( T% }3 G7 S( ?/ ^
当 sizeof 作用于数组时,求取的是数组所有元素所占用的大小。 int A[3][5];% x6 R! K# }* X4 m( b# L' ?char c[]="abcdef"; double*(*d)[3][6]; cout<<sizeof(A)<<endl; //输出60" F: l s; o/ ]* [' b: G3 j1 n4 \ cout<<sizeof(A[4])<<endl; //输出20 cout<<sizeof(A[0][0])<<endl;//输出4 cout<<sizeof(c)<<endl; //输出74 Y0 q( o" J8 f4 P cout<<sizeof(d)<<endl; //输出4 cout<<sizeof(*d)<<endl; //输出72 cout<<sizeof(**d)<<endl; //输出24& x3 t) p/ h% p7 A cout<<sizeof(***d)<<endl; //输出4 cout<<sizeof(****d)<<endl; //输出8' m5 a3 w; \% L# N A 的数据类型是 int[3][5] ,A[4] 的数据类型是 int[5],A[0][0]数据类型是int 。所以: sizeof(A)==sizeof(int[3][5])==3*5*sizeof(int)==60; ]1 S5 G( c/ r0 ]+ [1 ssizeof(A[4])==sizeof(int[5])=5*sizeof(int)==20) H" y. u% [1 b, ?. `0 K6 r4 N 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[]): V* v& c* ]8 N4 J/ Q+ |& O{( I! v6 p3 L0 ? return sizeof(str);! Q! p8 F+ p4 l, t( I. O } ; o7 z4 a- ], Q! J int main()" v1 Q7 Q( z0 m, l' M$ s { char szStr[] = "abcdef"; cout<< GetStrLength() << endl;% |4 _( P" y/ x( [) F return 0; } 输出不是 7 ,这里函数参数 str[] 已不再是数组类型,而是蜕变成指针,我们调用函数 GetStrLength() 时,程序会在栈上分配一个大小为 7 的数组吗?不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以 str 自然为指针类型 (char*) ,输出值为:4 。
对于 struct 数据结构由 CPU 的对齐问题导致 struct 的大小变得比较复杂。具体可以查看以前的文章一文轻松理解内存对齐。 理论上,int 占 4byte , char 占一个 byte ,那么将它们放到一个结构体中应该占 4+1=5byte ;但是实际上,通过运行程序得到的结果是 8byte 。 #include<stdio.h>8 X3 s' ]- g2 @, _& L) O" T$ ^% } struct{ int x;, Z' M5 R+ x* s char y; }Test; int main() { printf("%d\n",sizeof(Test)); // 输出8不是5; x! _. i4 p" w- Q) Q* V return 0; }5 l) v, Y7 d4 u; k 结构体的大小跟结构体成员对齐有密切关系,而并非简单地等于各个成员的大小之和!比如对如下结构体两个结构体 A、B 使用 sizeof 的结果分别是:16,24。可以看出 sizeof(B) 并不等于 sizeof(int)+sizeof(double)+sizeof(int)=16 。 struct A6 Z: r+ K2 N% F. n{% j' c: H% S. |1 h" F+ j) z int num1; int num2;6 }/ E6 a/ P9 _1 {6 L2 o: k double num3;4 Z5 v( z) C+ i- Q+ a w };6 _9 w8 l# \% c struct B { int num1;: L$ _8 | l" X5 V) b5 s; b$ A double num3; int num2;0 b1 b- J) X% s7 D: b* i8 o }; 结构体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 - C0 b" q3 ]4 n$ ^0 x{ public: int b; float c; & @! [& Y' Z# G3 T char d; , _ p1 k4 F0 b# F% J: m };' u, ?* i9 s+ l" D class B1 p- k8 {4 W5 {2 h' [ { }; ( C) y9 h! A# I# m" X6 L5 k8 V int main(void) # @+ E# S; ]% k" O' T1 q% f { 5 a! H i9 Y2 a# V; I% L cout << “sizeof(A) is ” << sizeof(A) << endl; ! y' H* o& A* @5 U6 V$ j //输出结果为129 r6 x( {' f9 ^# N8 @' t0 M: \ cout << “sizeof(B) is ” << sizeof(B) << endl; ' w6 ~- A, N1 C) F! a4 e* K //输出结果为1 return 0 ; " X% r2 \$ f2 ^% ^ } v/ J. k/ I/ V0 \$ t/ L1 [
{ public: 7 t3 b( D- h# \5 p. d) l! j: `: B static int a; : f% Y* v3 m' b! v, V int b; ( Z0 M# n( q1 V float c; / l% p0 Q' W% ?* g3 A6 \ char d; }; ' y6 X/ ]- g9 ?* } int main() - g1 b" J" C* m$ g! p7 X A { A object; cout << “sizeof(object) is ” << sizeof(object) << endl; / S: \7 D! y1 L+ o. r //输出结果为12 return 0 ; }$ F# G0 g; c& P" w 因为在程序编译期间,就已经为 static 变量在静态存储区域分配了内存空间,并且这块内存在程序的整个运行期间都存在。而每次声明了类 A 的一个对象的时候,为该对象在堆上,根据对象的大小分配内存。
{ 3 k+ G$ U6 k0 b; o& h( k. p public: static int a; int b; float c; char d; , l# y; J% |5 k$ n3 I* m- R, E int add(int x,int y) 3 t* K9 h5 B% ]% p A7 X6 h: G { " a. q* [# {; d7 { return x+y; - B: ~5 j* J1 W } }; int main() { " h* e- K2 p8 |& `. p- W A object; cout << “sizeof(object) is ” << sizeof(object) << endl; $ P, g7 Y0 U3 Y0 W N" X: ~# S b = object.add(3,4); 7 E9 h: Q5 z8 N) A0 A; _ cout << “sizeof(object) is ” << sizeof(object) << endl; //输出结果为12 return 0 ; % [7 t+ B( Y9 \+ V% S* ~/ B* `. K } 因为只有非静态类成员变量在新生成一个object的时候才需要自己的副本。所以每个非静态成员变量在生成新object需要内存,而function是不需要的。 3 sizeof 与 strlen 区别
sizeof(ss)=80, //ss表示在内存中的大小,20*4。 strlen(ss) //错误,strlen的参数只能是char*,且必须是以“\0”结尾的。 char *ss="0123456789";3 Z8 F) e) s$ r sizeof(ss)=4, //ss是指向字符串常量的字符指针。 sizeof(*ss)=1, // *ss是第一个字符。$ D; x0 Z# P3 Y) x& e& ?3 A( ~& P |