1. 我们如何设计一个结构体,让他大小合适(既要满足对齐规则,又要尽可能小)?
尽可能将小的结构体成员往前放
2. 如果不定义结构体变量,怎么计算结构体各个成员的相对偏移量?
struct A
{
char a;
short b;
int c;
float d;
double e;
long long int f;
};
这个结构体A所占字节数是多少?结构体变量f相对偏移了多少个格子?
分析:先分析前面,结构体A所占字节数:char类型变量a占一个字节,short类型占2个字节,这样的话不满足结构体对齐规则的第2条,因此给1+1=2,再去+2,这样的话,已经有4个字节,后面的类似,因此结构体A所占字节大小为 1+1+2+4+4+4+8+8=32
用编译器验证一下,如下
那么相对偏移量如何理解呢?
先从字面意思上说,偏移量就是偏移的数量,相对偏移量就是相对于某一个变量偏移的数量,那具体在编译器中也是这样吗?来看一下,我们首先用格子来代表每个变量所占的字节大小,图如下,画的比较粗糙,但能说明问题就行,从图中可以看出,对应的格子就是每一个变量的起始位置,每个变量下面的数字就是每个变量相对于开始位置所偏移的格子数,因此,从图中可以很明白的看出,结构体中个成员偏移说的是结构体中每个变量相对于开始地址偏移的数量,所以,a相对于起始位置偏移了1个格子,b相对于起始位置偏移了2个格子,c相对于起始位置偏移了4个格子,d相对于起始位置偏移了8个格子,e相对于起始位置偏移了16个格子,f相对于起始位置偏移了24个格子。
用编译器如何计算偏移呢?
① 这样,我们先定义一个struct A类型的变量tmp,通过 . 去访问结构体中的变量f,即就有tmp.f,ra然后对其取地址,再对tmp本身取地址(其实它相当于首元素的地址,也就是上面图中a刚开始的地址),让 &(tmp.f) - &(tmp),用一个int类型变量t去接收,有int t= &(tmp.f) - &(tmp);,但是这样写的话会报错,因为等式左边是int类型,右边是取地址的,我们就要将右边强转为char *,这块要是强转成 char类型,然而结构体中的变量所占字节数很大 ,超出其范围,因此,这块记得强转为char *。
② 如果不能定义一个结构体变量tmp,如何计算它的偏移量?
在这块假设其开始地址为0,还是用地址-地址,不再用上述定义的变量tmp,而是虚拟出来一个结构体,可以将0当作地址使用,强转为一个结构体指针类型,即struct A*,((struct A*)0),结构体指针访问其结构体中的成员通过 -> 访问,假设要访问其成员 f ,有((struct A*)0)->f,对其取地址&(((struct A*)0)->f),这就相当于减去其开始位置,因为每次都是 从0地址开始,用一个整型变量dist去接收,int dist = (int)&(((struct A*)0)->f),程序如下
③ 在②的基础上,我们先用一个宏定义去定义(int)&(((struct A*)0)->f),有#define MY_OFFSER(type,arg) ((int)&(((type*)0)->arg)) ,MY_OFFSER( )括号中的第一个元素是类型,第二个元素为变量,然后将这个宏函数变为((int)&(((type*)0)->arg)),因此,这块就直接可以用MY_OFFSER( A, f),代码如下
总结:计算偏移量时,在编辑器中可以通过以上3种方法进行编写,需要记住每种方法所表示的含义;(对这些有的不好理解,可以画个图,便于理解)。
再来验证一下结构体A的成员d的偏移量是8(由图中看出)