C语言-结构体 字节对齐

由于结构体存在字节对齐,所以结构体所占字节大小不是其各成员所占字节数之和!!

例1:下面程序结果为12,不是6!

#include<stdio.h>
struct Node
{
	char cha;
	int ia;
	char chb;
};
int main()
{
	struct Node sd;
	printf("%d\n", sizeof(sd));//12
	return 0;
}

该结构体变量在内存中的表示形式:

 假设以0地址作为首地址。cha占一个字节,但由于ia相对于首地址的偏移量要是int(4字节)的整数倍,故自动填充三个字节。其余同理。

一、由于存储变量地址对齐的问题,计算结构体大小的三条规则如下:

1.结构体变量的首地址(通常取0地址),必须是结构体变量中的“最大基本数据类型成员”所占字节数的整数倍!

2.结构体变量中每个成员相对于首地址的偏移量都是该成员基本数据类型所占字节数的整数倍! 

3.结构体变量的总大小,为结构体变量中“最大基本数据类型成员所占字节数”的整数倍。

例2:对于结构体成员变量为数组的并不是将其看作一个整体,而是拆成一个个相同类型的变量。

#include<stdio.h>
struct Node
{
	char ch[5];
	/*char ch0;
	char ch1;
	char ch2;
	char ch3;
	char ch4;*/
	int ia;
};
int main()
{
	struct Node sd;
	printf("%d\n", sizeof(sd));// 12
	return 0; 
}

将char ch[5] 看作char ch0,char ch1,char ch2,char ch3,char ch4五个字符类型变量,再根据字节对齐规则进行分配空间即可。

例3:嵌套结构体所占字节个数

#include<stdio.h>
struct sdate
{
	int year;
	int month;
	int day;
};
struct Student
{
	char s_id[10];
	char s_name[8];
	struct sdate birthday;
	double grade;
};
int main()
{
	struct Student s1;
	printf("%d\n", sizeof(s1)); //40
	return 0;
}

同理,遇到数组全打开为一个个的变量。对于char s_id[10] 占10个字节(默认首地址取0地址),由于10可以整除1,故直接在内存中放char s_name[8] 占8个字节。现在共占18个字节,接下来嵌套结构体sdate,对于sdate结构体,其所占字节总数为12个字节,由于sdate结构体中最大基本数据类型为int整型4字节。故由于相对首地址的偏移量要为最大基本数据类型字节数整数倍(4的整数倍),故18->20(填充两个字节),再将sdate结构体放入内存中,现在内存有20+12=32字节。接下来对于double grade,由于32为8的整数倍,故直接放入内存。最终Student结构体所占字节总数为40byte(40可以整除两个结构体中最大基本基本数据类型double字节数)。

Student结构体在内存中的表现形式如图:

附加:sizeof(long int)=4 byte,sizeof(long long)=8 byte。

附加题:

#include<stdio.h>
struct Mail
{
	char add[30];
	long int zip;
	double salary;
};
struct Employee
{
	char name[25];
	struct Mail addinfo;
	long int num;
};
int main()
{
	struct Employee s1;
	printf("%d\n", sizeof(s1)); //88
	return 0;
}

 唯一需要注意的是:对于嵌套结构体,总字节数算出来84byte还要满足可以整除两个结构体中最大基本数据类型成员字节数的规则。故84byte->88byte(8的整数倍)。

二、为什么要理解字节对齐问题?

 三、指定对齐值

预处理指令#pragma pack(n) 可以改变默认对齐数进行字节对齐。n 取值为1,2,4,8,16

VS系统中默认值为8,gcc默认值为4。

注:若结构体成员变量字节数均<n,则按照各自字节数进行字节对齐即可。

例1:(若n=8,则仍按照各自字节数进行字节对齐,结果为12byte)

#include<stdio.h>
#pragma pack(4)
struct Node
{
	char cha;
	int ia;
	short sa;
};
int main()
{
	struct Node s1;
	printf("%d\n", sizeof(s1));//12
	return 0;
}

具体在内存中分布如下图:

 思考题:

1.在设计结构体时,如何做到既满足字节对齐,又节省空间?

在设计结构体时:将结构体成员变量按照字节数依次从大到小或从小到大排列即可。

2.如何计算结构体成员的相对偏移量?

(1)允许定义结构体变量(作差!)

n = ((char*)&node.ia - (char*)&node);//ia的偏移量=成员变量ia的地址-node结构体变量首地址

或者:int n = ((int) & node.ia - (int)&node); 

#include<stdio.h>
struct Node
{
	char cha;
	double dx;
	short sa;
	int ia;
	char str[5];
	int ib;
};
int main()
{
	struct Node node;
	int n = ((char*)&node.ia - (char*)&node);//ia的偏移量=成员变量ia的地址-node结构体变量首地址
    //或:int n = ((int) & node.ia - (int)&node);
	printf("%d\n", n);
	return 0;
}

(2)不允许定义结构体变量(利用结构体指针变量)

        struct Node*p=NULL;
        int n = (int)&(p->ia);

(3)计算类型为type的成员item的偏移量的宏

        #define my_offset(type,item) ((int)&(((type*)0)->item))

例如:int n=my_offset(struct Node,ia);

  • 6
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值