先看一个sizeof(结构体)的例子1:
#include <stdio.h>
#include <iostream>
using namespace std;
typedef struct number
{
int i_data;
char c_data;
double d_data;
float f_data;
}NUM;
int main()
{
NUM num = {4,'b',10.2,5};
NUM *m = (NUM *)malloc(sizeof(NUM));
m = #
printf("sizeof(num) = %d\n",sizeof(num));
printf("address of num is 0x%x\n",&num);
printf("address of num.i_data = 0x%x\t0x%x\n",&(m->i_data),&(num.i_data));
printf("address of num.c_data = 0x%x\t0x%x\n",&(m->c_data),&(num.c_data));
printf("address of num.d_data = 0x%x\t0x%x\n",&(m->d_data),&(num.d_data));
printf("address of num.f_data = 0x%x\t0x%x\n",&(m->f_data),&(num.f_data));
system("pause");
return 0;
}
输出结果来看一下:
首先我的机器是windows32位的,sizeof(int)=4,sizeof(char)=1,sizeof(double)=8,sizeof(float)=4
计算得到的sizeof(num)=24, 我们所知道的结构体的大小应该是4+1+8+4=17,但是结果为什么是24呢?
计算机为了方便处理器和内存之间的数据传输和提高读取数据的速度,对基本类型的数据在内存中的存放位置进行了一定的限制。
首地址的值必须是某个数k(4/8)的倍数,这就是所谓的内存对齐。k被称为对齐模数。
1)最大的数据类型是double=8byte,则首地址必须是8的倍数。
2)结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要,编译器会在成员之间加上填充字节。
3)结构体总的大小是最大数据类型的倍数,24/8=3
可是明明有4个数据,为什么倍数是3呢?
因为sizeof(int)+sizeof(char)=5<8,所以int和char总共占了8个字节。
i_data的地址是0x28f95c,向后移4个字节存储c_data,因为考虑到要对齐,所以存完char后会空出3个字节。
d_data的地址是0x28f964,double占8个字节,所以下一个数据的地址是在这个地址的基础上加8.
下面的图可以清楚的表达:
下面我们稍微修改一下代码,去掉float类型的变量,再改变char类型变量的位置:
#include <stdio.h>
#include <iostream>
using namespace std;
typedef struct number
{
int i_data;
double d_data;
char c_data;
}NUM;
int main()
{
NUM num = {4,5.4,'d'};
NUM *m = (NUM *)malloc(sizeof(NUM));
m = #
printf("sizeof(num) = %d\n",sizeof(num));
printf("address of num is 0x%x\n",&num);
printf("num.i_data num[0x%x] = %d\n",&(m->i_data),num.i_data);
printf("num.d_data num[0x%x] = %.1f\n",&(m->d_data),num.d_data);
printf("num.c_data num[0x%x] = %c\n",&(m->c_data),num.c_data);
system("pause");
return 0;
}
输出结果如下:
可以看出少了一个数据,但是结构体的大小却没有变,还是24个字节,并且结构体成员之间的地址间隔都是8个字节。