C语言之结构体structWord文档格式.docx
《C语言之结构体structWord文档格式.docx》由会员分享,可在线阅读,更多相关《C语言之结构体structWord文档格式.docx(11页珍藏版)》请在冰豆网上搜索。
![C语言之结构体structWord文档格式.docx](https://file1.bdocx.com/fileroot1/2022-12/12/0477ff01-9c77-4dba-a2a0-492826e859f8/0477ff01-9c77-4dba-a2a0-492826e859f81.gif)
结构体所占用的内存与其成员在结构体中的声明顺序有关,其成员的内存对齐规则如下:
1)每个成员分别按自己的对齐字节数和PPB(指定的对齐字节数,32位机默认为4)两个字节数最小的那个对齐,这样可以最小化长度。
2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。
3)结构体对齐后的长度必须是成员中最大的对齐参数(PPB)的整数倍,这样在处理数组时可以保证每一项都边界对齐。
4)计算结构体的内存大小时,应该列出每个成员的偏移地址,则其长度=最后一个成员的偏移地址+最后一个成员数的长度+最后一个成员的调整参数(考虑PPB)。
下面举例说明上述规则:
#include"
stdio.h"
#pragmapack
(2)//指定PPB为2
structT
{
//偏移地址0
intb;
//偏移地址2
charc;
//偏移地址6
};
#pragmapack()//恢复原来默认PPB,32位下为4
structTTestData;
intmain(intargc,char*argv[])
TestData.a=1;
TestData.b=260;
printf("
%d\n"
sizeof(structT));
&
TestData.a);
TestData.a);
return0;
}
最后输出的结果为:
8。
语句#pragmapack
(2)的作用是指定结构体按2字节对齐,即PPB=2。
分析如下:
变量a默认为1字节,PB=2,所以a按1字节对齐,a的偏移地址为0。
变量b默认为4字节(在32位机器中int为4字节),PB=2,所以b按2字节对齐,b的偏移地址为2。
变量c默认为1字节,PB=2,所以c按1字节对齐,偏移地址为6。
此时结构体的计算出的字节数为6个字节。
最后按规则3,结构体对齐后的字节数为8。
sizeof(T)=6+1+1=8
1)范例1
structT{
charb;
//偏移地址1
intc;
则sizeof(T)=最后一个成员的偏移地址+最后一个成员数的长度=2+4=6。
-------------------------
2)范例2
structT1{
//偏移地址4
structT2{
//偏移地址8
PPB=4,则sizeof(T1)=4+4=8;
sizeof(T2)=8+1=9,9不能整除4,故调整数为3,即sizeof(T2)=8+1+3=12
1)字节对齐取决于编译器;
2)一定要注意PPB大小,PPB大小由pragampack(n)指定;
3)结构体占用的字节数要能被PPB整除。
1)说明:
(1)sizeof也可以对一个函数调用求值,其结果是函数返回类型的大小,函数并不会被调用。
(2)终于搞懂struct结构体内存分配问题了,结构体中各个成员字节对齐遵循以下几个原则:
直接用下面几个原则即可判断结构体的大小
-----------------------
2)结构体每个成员相对于结构体首地址的偏移量(offset)都是(这个)成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internaladding);
例如有以下一个结构体
structex
inti;
//4字节
chart;
//1字节
intn;
第1个成员偏移量为0,是int型成员大小4(假设这台机器的整型长度占4个字节)的整数倍。
第2个成员t为char型,它的大小为1,首先假设在成员i和t之间没有填充字节,由于i是整型,占4个字节那么在没有填充之前,第2个成员t相对于结构体的偏移量为4,他是t成员大小1的4倍,符合此条件,所以系统在给结构体第2个成员分配内存时,不会在i和t之间填充字节以到达对齐的目的。
当分配结构体第3个成员n时,首先发现是一个整型数据,大小为4,没有填充之前,n相对于结构体首地址偏移量为:
前面2个成员+填充字节=5,所以当系统发现5不是4(成员大小)的整数倍时,会在成员t之后(或者说n之前)填充3个字节,以使n的偏移量到达8而成为4的整数倍。
这样这个结构体占用内存情况暂时为4+1+3+4。
3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailingpadding)。
上面的结构体内存分配以后还要看是否满足此条件,假设在最末一个成员之后不需填充字节数,那么这个结构体的大小为12。
而ex结构体中最宽基本类型成员为int,大小为4,12为4的整数倍,所以无须再在最末一个成员之后加上填充字节了。
所以sizeof(ex)=12;
如果一个结构体如下所示
structex1{
//1字节+3字节
charadd;
那么sizeof(ex1)=16;
原因就是在最后一个成员之后填充了3个字节。
4)还有一个额外的条件:
结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
5)对于结构体成员属性中包含结构体变量的复合型结构体再确定最宽基本类型成员时,应当包括复合类型成员的子成员。
但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。
6)总结出一个公式:
结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:
sizeof(struct)=offsetof(lastitem)+sizeof(lastitem)+sizeof(trailingpadding)
例子1:
加密对照表
structtable
charinput,output;
};
structtabletranslate[]=
//建立加密对照表
'
a'
'
d'
b'
w'
c'
k'
;
'
e'
i'
'
structtable
//上面红字部分内容等同于下面绿字内容,也与例子2类同
charinput;
charoutput;
}translate[9]=
{//建立加密对照表
{'
},
intmain(void)
{
charch;
structtable*p,*pend;
//p和pend为指向结构table的指针
pend=&
translate[sizeof(translate)/sizeof(structtable)-1];
//pend指向结构数组translate的最后一个元素,sizeof(translate)=18,sizeof(structtable)=2
while((ch=getchar())!
='
/n'
)
for(p=translate;
p->
input!
=ch&
&
p!
=pend;
p++);
if(p->
input==ch)
putchar(p->
output);
else
putchar(ch);
例子2:
正弦波取点
structffts
doublereal;
doubleimag;
}DFTSWN[2][16]=
{1.000000e+00,-0.000000e+00},
{9.238795e-01,-3.826834e-01},
{7.071068e-01,-7.071068e-01},
{3.826834e-01,-9.238795e-01},
{-8.269461e-16,-1.000000e+00},
{-3.826834e-01,-9.238795e-01},
{-7.071068e-01,-7.071068e-01},
{-9.238795e-01,-3.826834e-01},
{-1.000000e+00,1.653892e-15},
{-9.238795e-01,3.826834e-01},
{-7.071068e-01,7.071068e-01},
{-3.826834e-01,9.238795e-01},
{2.480838e-15,1.000000e+00},
{3.826834e-01,9.238795e-01},
{7.071068e-01,7.071068e-01},
{9.238795e-01,3.826834e-01},
{1.000000e+00,-3.307784e-15},
{-4.134730e-15,-1.000000e+00},
{-1.000000e+00,4.961676e-15},
{4.900444e-15,1.000000e+00},
例子3:
结构体数组与指针
intdata[5]={10,20,30,40,50,};
//data整型数组
structs
intx;
int*y;
//y结构中的成员是指向整型的指针
}*p;
//p指向结构的指针
structsarray[5]=
//array结构数组
100,&
data[0],200,&
data[1],300,&
data[2],400,&
data[3],500,&
data[4]
intmain(void)
p=array;
//指针p指向结构数组的首地址
printf("
Forprinter:
\n"
);
p->
x);
//取结构指针p指向的结构的成员x的值,输出100
(*p).x);
//取结构指针p的内容的成员x的值,功能同上,输出100
*p->
y);
//取结构指针p的指针成员y的内容,输出10
*(*p).y);
//取结构指针p的内容的指针成员y的内容,功能同上,输出10
++p->
//
p所指的x加1,x先加1后再输出101,p不加1
///////////////////////////()优先级大于->
,->
优先级大于++,++优先级大于*
///////////////////////////
(++p)->
//p先加1后再取x的值,x不加1,输出200
x++);
//先取x的值后x再加1,输出200
//输出201
++(*p->
y));
//p所指的y的内容先加1,输出21,p不加1,y也不加1
++*p->
//同上,由运算的结合性隐含了括号,输出22
*++p->
//y先加1后再取y的内容,输出30,p不加1,y的内容不加1
//输出201
*(++p)->
//p先加1后取所指y的内容,输出30
//输出300
*p->
y++);
//取p所指的y的内容,输出30,然后p所指的y加1
*(p->
y)++);
//取p所指的y的内容,输出40,然后p所指的y加1
*p++->
//取p所指的y的内容,输出50,然后p加1
//输出400