C语言,内存对齐,内存分配,地址操作,结构体(二)

时间:2021-08-22 02:30:23

上次在操作结构体地址的时候,本来想取结构体第二个成员变量的地址,就在第一个成员变量基址上增加了第一个成员变量的大小,但是发现结果不对

struct student
{
int a;
int b;
double c;
};
查看一下结构体的地址

        printf("stu size %d\n",sizeof(stu));
printf("stu.a address %x\n",&stu.a);
printf("stu.b address %x\n",&stu.b);
printf("stu.c address %x\n",&stu.c);
printf("stu+1 address %x\n",&stu+1);
结果如下:

stu size 16
stu.a address 28fed0
stu.b address 28fed4
stu.c address 28fed8
stu+1 address 28fee0
stu+1的地址正好比stu增加了sizefo(stu)。也就是说在结构体起始地址增加加1,不是简单增加一个字节,或者说向后顺推一个字节,而是增加了整个结构体的大小,移动sizeof(stu)大小,(寻找下一个结构体)。

c语言中,对指针加1,是将该指针向后移动 该指针存储数据类型的大小,也就是说指针增加一个的本意是寻找下一个存储相同数据类型的存储单元。

下面用几个数据类型验证一下:

int temp1;
int temp2;
printf("temp1 address %x\n",&temp1);
printf("temp2 address %x\n",&temp2);
地址如下:

temp1 address 28fecc
temp2 address 28fec8
temp1的地址高,现在我们队temp2的地址加1

printf("temp1 address %x\n",&temp1);
printf("temp2 address %x\n",&temp2);
printf("temp2+1 address %x\n",&temp2+1);
结果如下:

temp1 address 28fecc
temp2 address 28fec8
temp2+1 address 28fecc
temp2地址加1操作增加了4个字节,也就是int的大小

再看一下其他数据类型,还有数组

double temp4;
char temp5[5];
int temp6[5];

printf("temp3 address %x\n",&temp3);
printf("temp3+1 address %x\n",&temp3+1);
printf("temp4 address %x\n",&temp4);
printf("temp4+1 address %x\n",&temp4+1);
printf("temp5 address %x\n",&temp5);
printf("temp5+1 address %x\n",&temp5+1);
printf("temp6 address %x\n",&temp6);
printf("temp6+1 address %x\n",&temp6+1);
结果如下

temp3     address   28fedf
temp3+1 address 28fee0
temp4 address 28fed0
temp4+1 address 28fed8
temp5 address 28fecb
temp5+1 address 28fed0
temp6 address 28feb4
temp6+1 address 28fec8
temp3+1增加了1个字节,char类型

temp4+1增加了8个字节,double字节

temp5+1增加了5*1个字节,长度为5的char数组

temp6+1增加了5*4个字节,长度为5的int数组

话说回来,(&temp6+1)-(&temp)=?多少呢?,肯定是1了

如果用printf("stu.c-stu.b  address   %d\n",&stu.c-&stu.b)进行操作,编译器很直接

C语言,内存对齐,内存分配,地址操作,结构体(二)

假如我们想要通过结构体的首地址得到成员变量的地址,那就强制让编译器增加数据类型的长度

printf("stu.b  address   %x\n",(char *)&stu.a+sizeof(stu.a));
printf("stu.c address %x\n",(char *)&stu.a+sizeof(stu.a)+sizeof(stu.b));
结果如下:

stu.a  address   28fed0
stu.b address 28fed4
stu.c address 28fed8
stu.b address 28fed4
stu.c address 28fed8
最后再回到结构体上,本来还想再试试如何通过结构体首地址访问结构体变量或者通过结构体成员变量获得结构体首地址,结果发现linux内核中有两个宏offsetof和container_of。

offsetof宏:获得一个结构体变量成员在此结构体中的偏移量。

container_of宏:从结构体(type)某成员变量(member)指针(ptr)来求出该结构体(type)的首指针。