
sizeof判断结构的大小typedef struct {int a; char b;} A_t; typedef struct {int a;字符b; char c;} B_t; typedef struct {char a; int b; char c;} C_t; void main(){char * a = 0; cout << sizeof(a)<< endl; // 4 cout << sizeof(* a)<< endl; // 1-这可以理解cout << sizeof(A_t)<< endl; // 8 cout << sizeof(B_t)<< endl; // 8 cout << sizeof(C_t)<< endl; // 12}为什么会这样呢? 2.语法: sizeof具有三种语法形式,如下: 1)sizeof(对象); // sizeof(object); 2)sizeof(type_name); // sizeof(type); 3)对象的大小; // sizeof对象; 5.由于指针变量的sizeof用于存储地址,因此它当然等于计算机内部地址总线的宽度.

因此,在32位计算机上,指针变量的返回值必须为4(以字节为单位). 可以预期,在将来的64位系统中,指针变量的sizeof结果将为8. char * pc =“ abc”; int * pi;字符串* ps; char ** ppc =&pc;无效(* pf)(); //函数指针sizeof(pc); //结果为4 sizeof(pi); //结果为4 sizeof(ps); //结果为4 sizeof(ppc); //结果为4 sizeof(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作为数组元素的数量. 现在,您应该知道这是错误的. 是的,如何找到数组元素的数量?简单,通常通过以下两种方式: int c1 = sizeof(a1)/ sizeof(char); //总长度/单个元素的长度int c2 = sizeof(a1)/ sizeof(a1 [0]); // total第一个元素的长度/长度写在这里. 只是问一下,下面的c3和的值应该是多少? void foo3(char a3 [3]){int c3 = sizeof(a3); // c3 ==} void foo4(char a4 []){int = sizeof(a4); // ==}也许当您尝试回答的值时,我意识到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. 为什么?为什么我总是那个受伤的人?请不要沮丧,让我们考虑一下sizeof的定义-sizeof的结果等于对象或类型占用的内存字节数. 好吧,让我们看一下S1的内存分配: S1 s1 = {a,0xFFFFFFFF};定义完以上变量后,添加一个断点,运行程序,并观察s1所在的内存. 你找到了什么?以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下: 0012FF78: 61 CC CC CC FF FF FF FF发现了什么?为什么中间有3个字节的CC?看一下MSDN上的说明: 将sizeof应用于结构类型或变量时,它会返回实际大小,其中可能包括为对齐而插入的填充字节. 原来,这是传说中的字节对齐!一个重要的话题出现了.

为什么需要字节对齐?计算机组成原理告诉我们,这有助于加快计算机的访问速度,否则将花费更多的指令周期. 出于这个原因,编译器将默认处理结构(实际上,其他地方的数据变量也是如此),以便宽度2的基本数据类型(短等)位于可被2整除的地址处. width为4. 基本数据类型(int等)位于可被4整除的地址上,依此类推. 这样,可能需要在两个数字之间添加填充字节,因此整个结构的sizeof值会增加. 让我们交换char和int在S1中的位置: struct S2 {int i;字符c;};看看sizeof(S2)的结果是什么,它仍然是8吗?再次查看内存,结果发现在成员c之后还有3个填充字节. 为什么?不用担心,让我们总结以下规则. 字节对齐的详细信息与编译器的实现有关,但通常满足三个条件: 1)结构变量的第一个地址可以除以其最宽的基本类型成员的大小; 2)结构的每个成员都是相对的结构的第一个地址的偏移量是成员大小的整数倍. 如有必要,编译器将在成员之间添加内部字节. 3)结构的总大小是最大宽度的基本类型成员的大小的整数倍. 如有必要,编译器将在最后一个成员之后添加尾随填充.

对于上述标准,有几点需要解释: 1)并不是说结构成员的地址是其大小的整数倍,偏移量呢?由于点1的存在,我们只能考虑成员的偏移量,这使思考变得简单. 想一想为什么. 可以通过宏offsetof()获得结构成员相对于结构的第一个地址的偏移量,该偏移量也在stddef.h中定义,如下所示: #define offsetof(s,m)(size_t)& (((s *)0)-> m)例如,如果要在S2中获取c的偏移量,则方法为size_t pos = offsetof(S2,c); // pos等于4 2)基本类型是指上述类型对于内置数据类型,例如char,short,int,float和double,此处的“数据宽度”是指其sizeof的大小. 因为结构的成员可以是复合类型,例如另一个结构sizeof计算结构体大小,所以在查找最宽的基本类型成员时,应包括复合类型成员的子成员,而不是将复合成员作为一个整体来对待. 但是,在确定复合类型的构件的偏移位置时,将复合类型视为整体. 这里的描述有点草率,想起来也有点草草,让我们看一下示例(具体值仍然是VC6作为示例,以后将不再描述): struct S3 {char c1; S1 s;字符c2}; S1最宽的简单成员的类型为int,而S3在考虑最宽的简单类型的成员时认为S1被分解,因此S3的最宽简单类型为int. 这样,由S3 It定义的变量的存储空间的第一个地址需要除以4,并且整个sizeof(S3)值也应除以4.
c1的偏移量为0,那么s的偏移量呢?此时,s是一个整体. 作为结构变量,它还满足前三个条件,因此其大小为8,偏移量为4,并且在c1和s之间以及c2和s之间需要3个填充字节. 不需要,所以c2的偏移量是12,c2的大小是13,并且13不能被4整除,因此末尾有3个填充字节. 最后,sizeof(S3)的值为16. 通过上面的描述,我们可以获得一个公式: 结构的大小等于最后一个成员的偏移量加上它的大小加上末尾的填充字节数sizeof计算结构体大小,即: sizeof(结构)= offsetof(最后一项)+ sizeof(最后一项)+ sizeof(尾随填充)在这里,朋友应该对结构的sizeof有新的认识,但是不要太高兴,没有提到影响sizeof的重要参数,那么这就是编译器的pack指令. 它用于调整结构的对齐方式. 不同编译器的名称和用法略有不同. 在VC6中,它是通过#pragma pack实现的. 您也可以直接修改/ Zp编译开关. #pragma pack(n)的基本用法是: #pragma pack(n),n是字节对齐数字,其值为1、2、4、8、16,如果该值大于sizeof值,则默认值为8. 的结构成员的小,则该成员的偏移量应基于此值,即结构成员的偏移量应取两者中的最小值,公式如下: offsetof(item)= min(n ,sizeof(item))再次查看示例: #pragma pack(push)//将当前包设置保存在堆栈上#pragma pack(2)// struct S1 {char c; int i;};结构体S3 {char c1; S1 s;字符c2}; #pragma pack(pop)//在计算sizeof(S1)时恢复先前的pack设置,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. C99规定可以将int,unsigned int和bool用作位字段类型,但是几乎所有编译器都对其进行了扩展,以允许存在其他类型. 使用位字段的主要目的是压缩存储. 一般规则是: 1)如果相邻位字段的类型相同,并且它们的位宽之和小于该类型的sizeof,则以下字段将存储在前一个字段的旁边. 直到无法容纳为止; 2)如果相邻位字段的类型相同,但是它们的位宽之和大于该类型的大小,则以下字段将从新存储单元开始,并且偏移量将是其新整数. 类型大小3)如果相邻位字段的类型不同,则每个编译器的具体实现也不同. VC6采用非压缩模式,Dev-C ++采用压缩模式; 4)如果非位散布在位字段之间,则域字段不会被压缩; 5)整个结构的总大小是最宽的基本类型成员的大小的整数倍.
让我们看一个例子. 示例1: 结构BF1 {char f1: 3; char f2: 4;字符f3: 5;};内存布局为: _f1__ | __f2__ | _ | ____ f3 ___ | ____ | | _ | _ | _ | _ | _ || _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | 03 78 1316位字段类型为char,第一个字节只能容纳f1和f2,因此f2被压缩为In 1个字节,f3只能从下一个字节开始. 因此,sizeof(BF1)的结果为2. 示例2: struct BF2 {char f1: 3;短f2: 4;字符f3: 5;};由于相邻位字段的类型不同,因此在VC6中其sizeof为6,在Dev-C ++中为2. 范例3: struct BF3 {char f1: 3;字符f2;字符f3: 5;};散布在其中的非位字段不会产生压缩,在VC6和Dev-C ++中获得的大小为3. 9.联合的sizeof结构在内存组织中是顺序的,并且联合是重叠的. 每个成员共享一部分内存,因此整个联合的sizeof是每个成员的最大sizeof. 结构的成员也可以是复合类型,其中复合类型成员被视为一个整体. 因此,在以下示例中,U的sizeof值等于sizeof(s). 联盟U {int i;字符c; S1 s;};
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-169953-1.html
_)
美国人那点手段不得人心
激进一点的买理财产品宜定盈里一年是1000块