2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > C语言:指针的偏移步长 结构体成员的偏移量 嵌套结构体成员的偏移量 结构体的内存对齐

C语言:指针的偏移步长 结构体成员的偏移量 嵌套结构体成员的偏移量 结构体的内存对齐

时间:2021-01-10 16:06:34

相关推荐

C语言:指针的偏移步长 结构体成员的偏移量 嵌套结构体成员的偏移量 结构体的内存对齐

文章目录

1 不同类型指针的偏移步长2 结构体成员的偏移量3 嵌套结构体成员的偏移量4 结构体的内存对齐4.1 内存对齐的原因与优点4.2 结构体内存对齐的规则4.3 结构体嵌套结构体时的对齐规则

1 不同类型指针的偏移步长

(1)不同类型的指针+1时,内存偏移的字节数不同。

char *类型指针 + 1,内存偏移 1 字节;

int *类型指针 + 1,内存偏移 4 字节;

double *类型指针 + 1,内存偏移 8 字节。

示例:

#include <stdio.h>//1.不同类型的指针+1时,偏移的字节数不同void func1() {char* p = NULL;printf("%p\n", p);//00000000printf("%p\n", p + 1);//00000001int* pp = NULL;printf("%p\n", pp);//00000000printf("%p\n", pp + 1);//00000004}

(2)对不同类型的指针解引用时,取出的字节数不同

示例:

#include <stdio.h>#include <string.h>//2.对不同类型的指针解引用时,取出的字节数不同void func2() {char buff[1024] = {0 };int num = 1234;//memset(buff, 0, sizeof(buff));memcpy(buff, &num, sizeof(num));char* p = buff;//将char*指针强转为int*类型指针后,再解引用printf("%d\n", *(int *)p);//1234}//3.对不同类型的指针解引用时,取出的字节数不同void func3() {char buff[1024] = {0 };int num = 1234;//memset(buff, 0, sizeof(buff));memcpy(buff + 1, &num, sizeof(num));char* p = buff;//将char*指针强转为int*类型指针后,再解引用printf("%d\n", *(int*)(p + 1));//1234}

2 结构体成员的偏移量

头文件<stddef.h>定义了标准宏

offsetof()宏可计算结构体成员的偏移量offsetof(结构体类型名 , 结构体成员名)

例:offsetof(struct Object, field);

示例:

#include <stdio.h>#include <stddef.h>//使用标准宏//结构体内存对齐(按数据类型长度最大的对齐-double 8字节对齐)struct Object {char a;//0 ~ 3int b;//4 ~ 7char buff[64];//8 ~ 71double c;//72 ~ 79};int main() {struct Object obj = {'a', 1, "hello world", 3.14 };/*offsetof()宏可计算结构体成员的偏移量(需包含<stddef.h>头文件)offsetof(结构体类型名 , 结构体成员名)*/printf("%d\n", offsetof(struct Object, a));//0printf("%d\n", offsetof(struct Object, b));//4printf("%d\n", offsetof(struct Object, buff));//8printf("%d\n", offsetof(struct Object, c));//72/* 通过结构体成员的指针偏移,可访问各个结构体成员将指向结构体的指针强转为(char *)类型,每次指针偏移的步长为1*/struct Object* p = &obj;//char*类型的起始地址,加上结构体成员的偏移量,再强转为指定结构体成员对应的指针类型,解引用获取指定结构体成员的值printf("%c\n", *( (char*)p + offsetof(Object, a) ));//a (ASCII码 97)printf("%d\n", *(int *)( (char*)p + offsetof(Object, b) ));//1//打印输出字符串类型时,无需解引用,使用字符串的首地址即可(默认至'\0'结束)printf("%s\n", ( (char*)p + offsetof(Object, buff) ));//hello worldprintf("%lf\n", *(double *)( (char*)p + offsetof(Object, c) ));//3.140000//通过结构体成员的偏移地址,解引用并修改对应结构体成员的值*(double *)((char*)p + offsetof(struct Object, c)) = 3.1415926;//修改结构体成员c的值printf("%lf\n", *(double *)((char*)p + offsetof(Object, c)));//3.141593return 0;}

3 嵌套结构体成员的偏移量

#include <stdio.h>#include <stddef.h>struct Inner {char a;int b;};struct Outer {char c;int d;struct Inner inner;};int main() {struct Outer outer = {'a', 1, {'b', 2} };/* 获取Outer结构体中嵌套的Inner结构体成员b *///1.通过结构体变量访问printf("%d\n", outer.inner.b); //2//2.通过2次指针偏移://(1)先获取嵌套结构体成员inner相对outer的偏移int offset1 = offsetof(struct Outer, inner);//(2)再获取属性b相对结构体inner的偏移int offset2 = offsetof(struct Inner, b);printf("%d\n", *(int*)((char*)&outer + offset1 + offset2));//2//3.通过1次指针偏移,获取指向嵌套结构体inner的指针,通过结构体指针访问成员printf("%d\n", ((struct Inner*)((char*)&outer + offset1))->b); //2return 0;}

4 结构体的内存对齐

4.1 内存对齐的原因与优点

内存未对齐的问题:CPU按块读取内存,当CPU访问数据时,若内存未对齐,则可能导致二次访问的情况,即前后两次访问的数据需拼接后才能获取指定数据。

内存对齐的优点以空间换时间,浪费部分用于对齐的空间,通过一次访问即可获取指定数据。

4.2 结构体内存对齐的规则

(1)内置数据类型:数据存储在该类型大小的整数倍上。

(2)自定义数据类型:依照特定的对齐规则。

①从第1个属性开始,从偏移量0位置开始存储;

②从第2个属性开始,从该数据类型大小对齐模数较小值的整数倍开始存储。即min {该数据类型大小 , 对齐模数} 的整数倍

③整体计算完毕后进行二次对齐,结构体的总大小必须是该结构体中最大数据类型对齐模数较小值的整数倍不足需补齐。即min {该结构体中最大数据类型 , 对齐模数} 的整数倍

注:使用#pragma pack(show)生成代码后查看”杂注”即默认对齐模数。默认对齐模数为8。

例:pragma pack(show) 的值 == 8

示例1:按默认对齐模数(8)对齐

#include <stdio.h>//#pragma pack(show)//对齐模数默认为8//生成后查看typedef struct {int a;//0 ~ 3char b;//4 → 4 ~ 7//double对齐后,补为4 ~ 7double c;//8 ~ 15float d;//16 ~ 19 → 16 ~ 23//二次对齐,补为16 ~ 23} StructA;int main() {printf("%d\n", sizeof(StructA));//24return 0;}

示例2:按指定对齐模数(1)对齐

#include <stdio.h>#pragma pack(1)//对齐模数为1typedef struct {int a;//0 ~ 3char b;//4//对齐模数为1,无需补齐double c;//5 ~ 12float d;//13 ~ 16//二次对齐,对齐模数为1,无需补齐} StructB;int main() {printf("%d\n", sizeof(StructB));//17return 0;}

4.3 结构体嵌套结构体时的对齐规则

①从第1个属性开始,从偏移量0位置开始存储;

②从第2个属性开始的非嵌套结构体属性,从该数据类型大小对齐模数较小值的整数倍开始存储。即min {该数据类型大小 , 对齐模数} 的整数倍

③从第2个属性开始的嵌套结构体属性,从该嵌套结构体中最大数据类型对齐模数较小值的整数倍开始存储。即min {该嵌套结构体中最大数据类型 , 对齐模数} 的整数倍

④整体计算完毕后进行二次对齐,结构体的总大小必须是该结构体中最大数据类型对齐模数较小值的整数倍不足需补齐。即min {该结构体中最大数据类型 , 对齐模数} 的整数倍

示例:结构体嵌套结构体时,按默认对齐模数(8)对齐

#include <stdio.h>#include <stddef.h>//默认对齐模数为8typedef struct {int a;//0 ~ 3char b;//4 → 4 ~ 7//double对齐后,补为4 ~ 7double c;//8 ~ 15float d;//16 ~ 19 → 16 ~ 23//二次对齐,补为16 ~ 23} Inner;//对齐模数为8时,二次对齐后,Inner结构体的大小为24typedef struct {int x; //0 ~ 3char y; //4 → 4 ~ 7 //嵌套结构体inner对齐后,补为4 ~ 7Inner inner; //8 ~ 31 //按嵌套结构体inner的最大数据类型(8)和对齐模数 对齐float z; //32 ~ 35 → 32 ~ 39//二次对齐,补为32 ~ 39} Outer; //对齐模数为8时,二次对齐后,Outer结构体的大小为40int main() {printf("内层结构体大小:%d\n", sizeof(Inner));//24printf("外层结构体大小:%d\n", sizeof(Outer));//40printf("属性x的偏移:%d\n", offsetof(Outer , x));//0printf("属性y的偏移:%d\n", offsetof(Outer , y));//4printf("属性inner的偏移:%d\n", offsetof(Outer , inner));//8printf("属性z的偏移:%d\n", offsetof(Outer , z));//32return 0;}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。