|
在 C/C++ 中,sizeof() 是一个判断数据类型或者表达式长度的运算符。! W; W2 I* |9 T) F2 j sizeof 是 C/C++ 中的一个操作符(operator),返回一个对象或者类型所占的内存字节数。
其返回值类型为 size_t ,在头文件 stddef.h 中定义为: typedef unsigned int size_t; 从sizeof 的定义可以看出:sizeof 不是一个函数,因为函数调用必须有一对括号。 #include <stdio.h>int main(void) {# T: ]" c7 V( w* o int num = 97;" ?" A( X1 N: G" U " n& S% I' H3 [( {. { printf("sizeof(num = 0)的值:%d\n",sizeof(num = 0)); printf("num 的值:%d\n",num); 8 D/ ? u3 a) `; h return 0; }; c1 n0 ~& w, H+ O* x
说明:sizeof 不是标准意义上的一元操作符,不支持链式表达式,sizeof 作用域范围内的语句不会编译成机器码,如 sizeof(num++) 中的 ++ 不执行。sizeof 也不是函数, sizeof 更像一个特殊的宏,在编译阶段求值。 2 sizeof 用法sizeof 有两种语法形式,如下: sizeof(type_name); //sizeof(类型);- o0 D* n$ h' O- `- b$ u6 ~sizeof (object); //或sizeof object 都属于 sizeof对象;/ a( u1 q8 I8 j/ s 所以: int i;: A* h2 O/ J' s% \( \sizeof(i); //合理3 j/ g3 B# P& [9 r! ]( | sizeof i; //合理# \% w3 J" U& i1 O. N5 f* {5 h; E sizeof(int); //合理1 n7 I7 p; a* i7 ]+ w sizeof int; //不合理
这里的基本数据类型是指short、int、long、float、double这样的简单内置数据类型。 由于它们的内存大小是和系统相关的,所以在不同的系统下取值可能不同。 #include <iostream>9 {8 V' m& @: B) `5 ?$ {! S3 k$ Lusing namespace std;1 m7 Q0 [) g0 l5 g: }4 H$ N* X* Y ( R/ _$ c6 u/ V C0 _: | 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;# Q2 Z. B& ?; d" T: e C4 ~, e 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;* W* Q# U% A7 ^: u# t6 [) b" ~ return 0; }- e3 D4 R8 ~4 F: a4 F% @) f 在 32 位系统下内置数据类型与其 sizeof 运算结果如下: Size of char : 1. F+ }( q; c1 ?( l( y2 vSize of int : 4 Size of short int : 2 Size of long int : 4 Size of float : 40 e. T0 l. [: [0 J8 Q5 x% [ Size of double : 8: _+ ~5 Q. ^, @# d1 W8 W2 K Size of wchar_t : 4: ` n+ l5 u" }4 _4 ^# ^7 C. `
指针主要用于存储地址,前几天文章C语言指针详解提到过,指针变量的位宽等于机器字长,机器字长由 CPU 寄存器位数决定。在 32 位系统中,一个指针变量的返回值为 4 字节, 64 位系统中指针变量的 sizeof 结果为 8 字节。 char *p =”hello”;sizeof( p ); // 结果为4 : ]4 `" h4 z- x( o sizeof(*p); // 结果为1 ( K6 W# r9 u5 ~& s2 Q5 } v% ` int *pi; * f" u# d4 N8 m sizeof( pi ); //结果为4 8 Z8 o" Z+ Z; M2 E2 z) `4 E sizeof(*pi); //结果为4 & e( [/ n0 G' L- L: L' m% D+ t char **pp = &p; sizeof( pp ); // 结果为4 6 H9 @6 |% j2 E$ _7 w9 v sizeof( *pp ); // 结果为4
函数类型以其返回类型作为自身类型,进行 sizeof 取值。 void fun1()5 q* Q3 R1 l, F4 r* J{ } int fun2()0 N. o+ `7 k9 o8 q/ s7 h5 L$ g8 i {7 h/ g h! O7 F7 X- [/ z return 0; } double fun3()& H& Y7 l6 j2 P7 ^/ ], E. k0 r { return 0.0; }; Z+ _. n' @0 w* q cout << sizeof(fun1()) << endl; //错误!无法对void类型使用sizeof1 c$ T) a* `7 g5 J( K cout << sizeof(fun2()) << endl; //fun2()返回值类型为int,输出4 cout << sizeof(fun3()) << endl; //fun3()返回值类型为double,输出8) J! a ^5 H& K; V4 ~
当 sizeof 作用于数组时,求取的是数组所有元素所占用的大小。 int A[3][5];/ ^9 o6 B! h1 Pchar c[]="abcdef"; double*(*d)[3][6]; I7 n1 `2 B5 X4 V1 H" ]% e: c cout<<sizeof(A)<<endl; //输出607 Y6 u7 E9 P3 C% y; A, x+ @2 q8 N cout<<sizeof(A[4])<<endl; //输出20 cout<<sizeof(A[0][0])<<endl;//输出4* R) U/ U9 y) J/ c! Q# E4 O, P cout<<sizeof(c)<<endl; //输出7 cout<<sizeof(d)<<endl; //输出4/ Z4 @& i5 s; D& J% Q3 |; A cout<<sizeof(*d)<<endl; //输出72 cout<<sizeof(**d)<<endl; //输出249 ?6 Y( f, \; P7 I& Y. {% l 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)==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[]){- X% F7 t5 t$ E$ Q% L2 E% s7 I) v* l return sizeof(str);" b F) d) w" B9 P }5 b8 k% Q6 X, S4 W 6 t6 n n& w1 y/ M int main() {' P* |5 ~ D0 F5 k, l* l. U char szStr[] = "abcdef";- g; X3 Y) O2 N cout<< GetStrLength() << endl; return 0; }1 E7 j& B8 o5 U% M A% E- ? 输出不是 7 ,这里函数参数 str[] 已不再是数组类型,而是蜕变成指针,我们调用函数 GetStrLength() 时,程序会在栈上分配一个大小为 7 的数组吗?不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以 str 自然为指针类型 (char*) ,输出值为:4 。
对于 struct 数据结构由 CPU 的对齐问题导致 struct 的大小变得比较复杂。具体可以查看以前的文章一文轻松理解内存对齐。 理论上,int 占 4byte , char 占一个 byte ,那么将它们放到一个结构体中应该占 4+1=5byte ;但是实际上,通过运行程序得到的结果是 8byte 。 #include<stdio.h>struct{' t0 R' _9 ^% V! D0 ]( o( q int x;8 k( ]" h( c/ \% q2 ] char y;% v9 l+ D: T$ n! }% J }Test; 2 @" i9 o( E$ @% D! R5 z int main() { printf("%d\n",sizeof(Test)); // 输出8不是5 return 0;6 l( F& q$ j% d2 D3 a: Q } 结构体的大小跟结构体成员对齐有密切关系,而并非简单地等于各个成员的大小之和!比如对如下结构体两个结构体 A、B 使用 sizeof 的结果分别是:16,24。可以看出 sizeof(B) 并不等于 sizeof(int)+sizeof(double)+sizeof(int)=16 。 struct A o" z" u& Z- R3 W) g0 i# Q{ int num1;0 K- M0 ~7 d+ Z2 Y7 Q# x int num2; double num3; }; struct B {' ?5 T' O o1 }: Y5 ]5 c int num1; double num3;& w( q7 x/ Y: W; Z f' U- ^2 W int num2;7 C9 ?5 A4 b6 x# L6 l- t4 l, z5 | h };, ~7 X* K3 w& z* C1 l% E) T! x+ f 结构体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 u/ |% _& h$ E{ 8 S9 N3 ~' j4 ~' T2 q$ \ public: int b; % H5 W& l: X* b# V3 ] float c; char d; & m+ I; t* `2 }! W9 V }; ~" R# c) s) G# P, v1 B class B { : P k: S: p) \5 V) E# ?" w }; & F6 ^* P% l) T% J% V int main(void) { 6 A, o4 o2 M/ q9 O a2 P cout << “sizeof(A) is ” << sizeof(A) << endl; //输出结果为123 ^+ D0 E; G' X7 V7 u cout << “sizeof(B) is ” << sizeof(B) << endl; //输出结果为1 return 0 ; }2 z5 \7 k: k8 S. `" `* G2 P* k
{ 8 J V6 E1 t8 }1 |( u public: static int a; int b; float c; char d; };$ y1 F* R1 U9 \ a4 X int main() { 3 H) J% P! T% b( ^# O A object; , e' W' j, h' P- G# e8 f cout << “sizeof(object) is ” << sizeof(object) << endl; //输出结果为12 return 0 ; } 因为在程序编译期间,就已经为 static 变量在静态存储区域分配了内存空间,并且这块内存在程序的整个运行期间都存在。而每次声明了类 A 的一个对象的时候,为该对象在堆上,根据对象的大小分配内存。
{ public: & b4 z9 r8 I7 @0 T, D* I+ C static int a; 3 [7 u, M' j N. r# v int b; " ]' N2 E7 z$ ~4 p/ z float c; 4 a( Z7 t# b* m0 Q9 I char d; int add(int x,int y) 7 y8 S% O8 H, ^, o6 [* t7 Q# \ { return x+y; , F. n. {# T: n- o- X; A* Q } % i* w+ `+ Z# W) g) l* I }; int main() { 3 m# ~+ r1 X6 A4 P* F. F A object; cout << “sizeof(object) is ” << sizeof(object) << endl; b = object.add(3,4); . U& v; B3 g t1 ?( I& p) Y cout << “sizeof(object) is ” << sizeof(object) << endl; //输出结果为12 |" U, T* R% W1 f w return 0 ; }' a" D* Y1 q( p 因为只有非静态类成员变量在新生成一个object的时候才需要自己的副本。所以每个非静态成员变量在生成新object需要内存,而function是不需要的。 3 sizeof 与 strlen 区别
sizeof(ss)=80, //ss表示在内存中的大小,20*4。 strlen(ss) //错误,strlen的参数只能是char*,且必须是以“\0”结尾的。/ \; {) ?" [8 j' a char *ss="0123456789";7 M _: ^! p7 ]! F0 K3 A# s' _: g sizeof(ss)=4, //ss是指向字符串常量的字符指针。* q) A! u* k) W0 z1 d+ m4 m sizeof(*ss)=1, // *ss是第一个字符。 |
微信公众号
手机版