sizeof进行结构体大小的判断
c++中关于结构体长度的计算问题

[C++]字节对齐与结构体大小[C++] 2010-09-24 21:40:26 阅读172 评论0 字号:大中小订阅说明:结构体的sizeof值,并不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题。
这些问题在平时编程的时候也确实不怎么用到,但在一些笔试面试题目中出是常常出现,对sizeof我们将在另一篇文章中总结,这篇文章我们只总结结构体的sizeof,报着不到黄河心不死的决心,终于完成了总结,也算是小有收获,拿出来于大家分享,如果有什么错误或者没有理解透的地方还望能得到提点,也不至于误导他人。
一、解释现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
各个硬件平台对存储空间的处理上有很大的不同。
一些平台对某些特定类型的数据只能从某些特定地址开始存取。
比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。
比如有些平台每次读都是从偶地址开始,如果一个int 型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。
二、准则其实字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则:1. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;2. 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
sizeof()的用法

sizeof()的⽤法1. 定义sizeof 是⼀个操作符 operator,不是⼀个函数,其作⽤是返回⼀个对象或类型所占的内存字节数---------------------------------------------------------------------------------------------------------2. 语法sizeof object; //sizeof 对象sizeof(object);sizeof(type_name); // 例如 sizeof(int)对象 object 可以是各种类型的变量,以及表达式(⼀般sizeof不会对表达式进⾏计算);sizeof对对象求内存⼤⼩,最终都是转化为对对象的数据类型进⾏求值;sizeof(表达式) 值为表达式的最终结果的数据类型的⼤⼩int i;sizeof(int); //值为4sizeof(i); //值为4,等价于sizeof(int)sizeof i; //值为4sizeof(2); //值为4,等价于sizeof(int),因为2的类型为intsizeof(2 + 3.14); //值为8,等价于sizeof(double),因为此表达式的结果的类型为doublechar ary[sizeof(int) * 10]; //OK,编译⽆误---------------------------------------------------------------------------------------------------------3. 基本数据类型的sizeof基本数据类型如int short long char double等,其内存⼤⼩与系统有关。
32位系统的int(4 Bytes), short(2 Bytes), long(4 Bytes), char(1 Bytes), double(8 Bytes), float(4 Bytes)4. 结构体的sizeof结构体的sizeof涉及到字节对齐问题,字节对齐有助于加快计算机的存取速度,减⼩指令周期。
sizeof()用法汇总

sizeof()功能:计算数据空间的字节数1.与strlen()比较strlen()计算字符数组的字符数,以"\0"为结束判断,不计算为'\0'的数组元素。
而sizeof计算数据(包括数组、变量、类型、结构体等)所占内存空间,用字节数表示。
2.指针与静态数组的sizeof操作指针均可看为变量类型的一种。
所有指针变量的sizeof 操作结果均为4。
注意:int *p; sizeof(p)=4;但sizeof(*p)相当于sizeof(int);对于静态数组,sizeof可直接计算数组大小;例:int a[10];char b[]="hello";sizeof(a)等于4*10=40;sizeof(b)等于6;注意:数组做型参时,数组名称当作指针使用!!void fun(char p[]){sizeof(p)等于4}经典问题:double* (*a)[3][6];cout<<sizeof(a)<<endl; // 4 a为指针cout<<sizeof(*a)<<endl; // 72 *a为一个有3*6个指针元素的数组 cout<<sizeof(**a)<<endl; // 24 **a为数组一维的6个指针cout<<sizeof(***a)<<endl; // 4 ***a为一维的第一个指针cout<<sizeof(****a)<<endl; // 8 ****a为一个double变量问题解析:a是一个很奇怪的定义,他表示一个指向double*[3][6]类型数组的指针。
既然是指针,所以sizeof(a)就是4。
既然a是执行double*[3][6]类型的指针,*a就表示一个double*[3][6]的多维数组类型,因此sizeof(*a)=3*6*sizeof(double*)=72。
c语言中sizeof的用法举例

c语言中sizeof的用法举例在C语言中,sizeof是一个用于计算数据类型或变量所占字节数的运算符。
它可以用于计算各种数据类型的大小,包括基本数据类型、数组、结构体和联合体等。
下面是一些使用sizeof运算符的示例:1. 计算基本数据类型的大小:c#include <stdio.h>int main() {printf("int类型的大小为:%zu 字节\n", sizeof(int));printf("float类型的大小为:%zu 字节\n", sizeof(float));printf("char类型的大小为:%zu 字节\n", sizeof(char));printf("double类型的大小为:%zu 字节\n", sizeof(double));return 0;}输出:int类型的大小为:4 字节float类型的大小为:4 字节char类型的大小为:1 字节double类型的大小为:8 字节2. 计算数组的大小:c#include <stdio.h>int main() {int arr[] = {1, 2, 3, 4, 5};int size = sizeof(arr) / sizeof(arr[0]);printf("数组的大小为:%d\n", size);return 0;}输出:数组的大小为:53. 计算结构体的大小:c#include <stdio.h>struct Student {char name[20];int age;float score;};int main() {struct Student stu;printf("结构体的大小为:%zu 字节\n", sizeof(stu));return 0;}输出:结构体的大小为:28 字节4. 计算联合体的大小:c#include <stdio.h>union Data {int num;float f;char str[20];};int main() {union Data data;printf("联合体的大小为:%zu 字节\n", sizeof(data));return 0;}输出:联合体的大小为:20 字节5. 计算指针类型的大小:c#include <stdio.h>int main() {int *ptr;printf("指针的大小为:%zu 字节\n", sizeof(ptr));return 0;}输出:指针的大小为:8 字节(在64位系统上)6. 计算自定义类型的大小:c#include <stdio.h>typedef struct {int x;int y;} Point;int main() {Point p;printf("自定义类型的大小为:%zu 字节\n", sizeof(p));return 0;}输出:自定义类型的大小为:8 字节总结:sizeof运算符可以用于计算各种数据类型的大小,包括基本数据类型、数组、结构体、联合体和指针等。
sizeof的使用方法

学过数据结构的你应该知道指针是一个很重要的概念,它记录了另一个对象的地址。既
然是来存放地址的,那么它当然等于计算机内部地址总线的宽度。所以在32位计算机中
,一个指针变量的返回值必定是4(注意结果是以字节为单位),可以预计,在将来的6
4位系统中指针变量的sizeof结果为8。
性强些。
4. 基本数据类型的sizeof
这里的基本数据类型指short、int、long、float、double这样的简单内置数据类型,
由于它们都是和系统相关的,所以在不同的系统下取值可能不同,这务必引起我们的注
意,尽量不要在这方面给自己程序的移植造成麻烦。
一般的,在32位编译环境中,sizeof(int)的取值为4。
sizeof是C语言的一种单目操作符,如C语言的其他操作符++、--等。它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。
二、sizeof的使用方法
1、用于数据类型
sizeof使用形式:sizeof(type)
2、int、unsigned int 、short int、unsigned short 、long int 、unsigned long 、float、double、long double 类型的sizeof 在ANSI C中没有具体规定,大小依赖于实现,一般可能分别为2、2、2、2、4、4、4、8、10。
};
sizeof( S.f1 );// error
3. sizeof的常量性
sizeof的计算发生在编译时刻,所以它可以被当作常量表达式使用,如:
c语言sizeof()计算空间大小为8

c语言sizeof()计算空间大小为8以C语言sizeof()计算空间大小为8为标题C语言中的sizeof()函数是一种用于计算数据类型或变量所占内存空间大小的运算符。
在C语言中,每个数据类型都有其特定的大小,sizeof()函数可以返回该数据类型或变量所占的字节数。
在C语言中,sizeof()函数的使用非常简单。
它的语法形式为sizeof(数据类型或变量)。
通过将需要计算大小的数据类型或变量作为参数传递给sizeof()函数,就可以得到该数据类型或变量所占的字节数。
sizeof()函数的返回值是一个无符号整数,表示数据类型或变量所占的字节数。
这个返回值的类型是size_t,它是一个定义在stddef.h头文件中的类型。
在C语言中,不同的数据类型所占的字节数是不同的。
下面是一些常见的数据类型及其所占的字节数:- char类型占用1个字节;- short类型占用2个字节;- int类型占用4个字节;- long类型占用4个字节;- float类型占用4个字节;- double类型占用8个字节;- long long类型占用8个字节。
需要注意的是,sizeof()函数返回的是数据类型或变量所占的字节数,并不是实际使用的内存大小。
在实际编程中,还需要考虑对齐问题。
对齐是为了提高内存的访问效率,使得数据在内存中的存储更加紧凑。
在C语言中,对齐是由编译器来处理的。
编译器会根据特定的规则,对数据进行对齐。
这些规则可以通过编译器的选项进行配置,以满足不同的需求。
对于结构体和联合体来说,其大小是由其成员的大小和对齐方式共同决定的。
在计算结构体或联合体的大小时,需要考虑成员的大小和对齐方式,并将其按照对齐方式进行对齐。
除了可以计算数据类型的大小外,sizeof()函数还可以用来计算数组的大小。
对于数组来说,sizeof()函数返回的是整个数组所占的字节数。
下面是一个使用sizeof()函数计算空间大小的示例:```c#include <stdio.h>int main() {int a = 10;printf("int类型所占的字节数:%zu\n", sizeof(int));printf("变量a所占的字节数:%zu\n", sizeof(a));int arr[] = {1, 2, 3, 4, 5};printf("数组arr所占的字节数:%zu\n", sizeof(arr));return 0;}```在上面的示例中,我们使用sizeof()函数计算了int类型、变量a 和数组arr所占的字节数,并通过printf()函数将结果输出到屏幕上。
sizeof的用法

全面解析sizeof的用法以下代码使用平台是Windows7 64bits+VS2012。
sizeof是C/C++中的一个操作符(operator),其作用就是返回一个对象或者类型所占的内存字节数,使用频繁,有必须对齐有个全面的了解。
1.Sizeof的基本语法sizeof有三种语法形式,如下:(1)sizeof( object ); // sizeof( 对象);(2)sizeof( type_name ); // sizeof( 类型);(3)sizeof object; // sizeof 对象;第三种语法结构虽然正确,为简单统一,均使用一、二中写法。
例如:int i;sizeof( i ); // oksizeof i; // oksizeof( int ); // oksizeof int; // error2.sizeof计算基本类型与表示式sizeof计算对象的大小也是转换成对对象类型的计算,也就是说,同种类型的不同对象其sizeof值都是一致的。
这里,对象可以进一步延伸至表达式,即sizeof可以对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,sizeof是编译时进行运算,与运行时无关,不会对表达式进行计算。
考察如下代码:#include<iostream>using namespace std;int main(int argc,char* argv[]){cout<<"sizeof(char)="<<sizeof(char)<<endl;cout<<"sizeof(short)="<<sizeof(short int)<<endl;cout<<"sizeof(int)="<<sizeof(int)<<endl;cout<<"sizeof(long)="<<sizeof(long int)<<endl;cout<<"sizeof(long long)="<<sizeof(long int int)<<endl;cout<<"sizeof(float)="<<sizeof(float)<<endl;cout<<"sizeof(double)="<<sizeof(double)<<endl;int i=8;cout<<"i="<<i<<endl;cout<<"sizeof(i)="<<sizeof(i)<<endl;cout<<"sizeof(i)="<<sizeof(i=5)<<endl;cout<<"i="<<i<<endl;}在64bits的Windows下运行结果是sizeof(char)=1sizeof(short)=2sizeof(int)=4sizeof(long)=4sizeof(long long)=4sizeof(float)=4sizeof(double)=8i=8sizeof(i)=4sizeof(i)=4i=8注意两点,第一:i的值并未发生改变,表明sizeof括号内的表达式并没有执行,sizeof在编译时求其表达式的运算结果的类型,sizeof运算与运行时无关。
C语言sizeof()用法介绍

C语⾔sizeof()⽤法介绍1. 定义sizeof是⼀个操作符(operator)。
其作⽤是返回⼀个对象或类型所占的内存字节数。
2. 语法sizeof有三种语法形式:1) sizeof (object); //sizeof (对象)2) sizeof object; //sizeof 对象3) sizeof (type_name); //sizeof (类型)对象可以是各种类型的变量,以及表达式(⼀般sizeof不会对表达式进⾏计算)。
sizeof对对象求内存⼤⼩,最终都是转换为对对象的数据类型进⾏求值。
sizeof (表达式); //值为表达式的最终结果的数据类型的⼤⼩举例:int i;sizeof(int); //值为4sizeof(i); //值为4,等价于sizeof(int)sizeof i; //值为4sizeof(2); //值为4,等价于sizeof(int),因为2的类型为intsizeof(2 + 3.14); //值为8,等价于sizeof(double),因为此表达式的结果的类型为doublechar ary[sizeof(int) * 10]; //OK,编译⽆误1. 基本数据类型的sizeof这⾥的基本数据类型是指short、int、long、float、double这样的简单内置数据类型。
由于它们的内存⼤⼩是和系统相关的,所以在不同的系统下取值可能不同。
2. 结构体的sizeof结构体的sizeof涉及到字节对齐问题。
为什么需要字节对齐?计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。
为此,编译器默认会对结构体进⾏处理(实际上其它地⽅的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,依次类推。
这样,两个数中间就可能需要加⼊填充字节,所以整个结构体的sizeof值就增长了。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
sizeof进行结构体大小的判断typedef struct{int a;char b;}A_t;typedef struct{int a;char b;char c;}B_t;typedef struct{char a;int b;char c;}C_t;void main(){char*a=0;cout<<sizeof(a)<<endl;//4cout<<sizeof(*a)<<endl;//1--这个能理解cout<<sizeof(A_t)<<endl;//8cout<<sizeof(B_t)<<endl;//8cout<<sizeof(C_t)<<endl;//12}为什么是这样的结果啊?2. 语法:sizeof有三种语法形式,如下:1) sizeof( object ); // sizeof( 对象);2) sizeof( type_name ); // sizeof( 类型);3) sizeof object; // sizeof 对象;5. 指针变量的sizeof既然是来存放地址的,那么它当然等于计算机内部地址总线的宽度。
所以在32位计算机中,一个指针变量的返回值必定是4(以字节为单位),可以预计,在将来的64位系统中指针变量的sizeof结果为8。
char* pc = "abc";int* pi;string* ps;char** ppc = &pc;void (*pf)();// 函数指针sizeof( pc ); // 结果为4sizeof( pi ); // 结果为4sizeof( ps ); // 结果为4sizeof( ppc ); // 结果为4sizeof( pf );// 结果为4指针变量的sizeof值与指针所指的对象没有任何关系,正是由于所有的指针变量所占内存大小相等,所以MFC消息处理函数使用两个参数WPARAM、LPARAM 就能传递各种复杂的消息结构(使用指向结构体的指针)。
6. 数组的sizeof数组的sizeof值等于数组所占用的内存字节数,如:char a1[] = "abc";int a2[3];sizeof( a1 ); // 结果为4,字符串末尾还存在一个NULL终止符sizeof( a2 ); // 结果为3*4=12(依赖于int)一些朋友刚开始时把sizeof当作了求数组元素的个数,现在,你应该知道这是不对的,那么应该怎么求数组元素的个数呢?Easy,通常有下面两种写法:int c1 = sizeof( a1 ) / sizeof( char ); // 总长度/单个元素的长度int c2 = sizeof( a1 ) / sizeof( a1[0] ); // 总长度/第一个元素的长度写到这里,提一问,下面的c3,c4值应该是多少呢?void foo3(char a3[3]){int c3 = sizeof( a3 ); // c3 ==}void foo4(char a4[]){int c4 = sizeof( a4 ); // c4 ==}也许当你试图回答c4的值时已经意识到c3答错了,是的,c3!=3。
这里函数参数a3已不再是数组类型,而是蜕变成指针,相当于char* a3,为什么?仔细想想就不难明白,我们调用函数foo1时,程序会在栈上分配一个大小为3的数组吗?不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以a3自然为指针类型(char*),c3的值也就为4。
7. 结构体的sizeof这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。
让我们先看一个结构体:struct S1{char c;int i;};问sizeof(s1)等于多少?聪明的你开始思考了,char占1个字节,int占4个字节,那么加起来就应该是5。
是这样吗?你在你机器上试过了吗?也许你是对的,但很可能你是错的!VC6中按默认设置得到的结果为8。
Why?为什么受伤的总是我?请不要沮丧,我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:S1 s1 = { a , 0xFFFFFFFF };定义上面的变量后,加上断点,运行程序,观察s1所在的内存,你发现了什么?以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:0012FF78: 61 CC CC CC FF FF FF FF发现了什么?怎么中间夹杂了3个字节的CC?看看MSDN上的说明:When applied to a structure type or variable, sizeof returns the actual size,which may include padding bytes inserted for alignment.原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。
为什么需要字节对齐?计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。
为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。
这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof 值就增长了。
让我们交换一下S1中char与int的位置:struct S2{int i;char c;};看看sizeof(S2)的结果为多少,怎么还是8?再看看内存,原来成员c后面仍然有3个填充字节,这又是为什么啊?别着急,下面总结规律。
字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
对于上面的准则,有几点需要说明:1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢?因为有了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。
想想为什么。
结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下:#define offsetof(s,m) (size_t)&(((s *)0)->m)例如,想要获得S2中c的偏移量,方法为size_t pos = offsetof(S2, c);// pos等于42) 基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。
由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。
但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。
这里叙述起来有点拗口,思考起来也有点挠头,还是让我们看看例子吧(具体数值仍以VC6为例,以后不再说明):struct S3{char c1;S1 s;char c2};S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。
c1的偏移量为0,s 的偏移量呢?这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。
最后得到sizeof(S3)的值为16。
通过上面的叙述,我们可以得到一个公式:结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:sizeof( struct ) = offsetof( last item ) + sizeof( last item ) + sizeof(trailing padding )到这里,朋友们应该对结构体的sizeof有了一个全新的认识,但不要高兴得太早,有一个影响sizeof的重要参量还未被提及,那便是编译器的pack指令。
它是用来调整结构体对齐方式的,不同编译器名称和用法略有不同,VC6中通过#pragma pack实现,也可以直接修改/Zp编译开关。
#pragma pack的基本用法为:#pragma pack( n ),n为字节对齐数,其取值为1、2、4、8、16,默认是8,如果这个值比结构体成员的sizeof值小,那么该成员的偏移量应该以此值为准,即是说,结构体成员的偏移量应该取二者的最小值,公式如下:offsetof( item ) = min( n, sizeof( item ) )再看示例:#pragma pack(push) // 将当前pack设置压栈保存#pragma pack(2)// 必须在结构体定义之前使用struct S1{char c;int i;};struct S3{char c1;S1 s;char c2};#pragma pack(pop) // 恢复先前的pack设置计算sizeof(S1)时,min(2, sizeof(i))的值为2,所以i的偏移量为2,加上sizeof(i)等于6,能够被2整除,所以整个S1的大小为6。
同样,对于sizeof(S3),s的偏移量为2,c2的偏移量为8,加上sizeof(c2)等于9,不能被2整除,添加一个填充字节,所以sizeof(S3)等于10。
现在,朋友们可以轻松的出一口气了,还有一点要注意,“空结构体”(不含数据成员)的大小不为0,而是1。
试想一个“不占空间”的变量如何被取地址、两个不同的“空结构体”变量又如何得以区分呢?于是,“空结构体”变量也得被存储,这样编译器也就只能为其分配一个字节的空间用于占位了。
如下:struct S5 { };sizeof( S5 ); // 结果为18. 含位域结构体的sizeof前面已经说过,位域成员不能单独被取sizeof值,我们这里要讨论的是含有位域的结构体的sizeof,只是考虑到其特殊性而将其专门列了出来。