下面有这样一段代码,请试着分析结果:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//struct aaa{
// int num;
// char name[20];
// double age;
// char sex;
//};
//int main(){
// struct aaa x;
// printf("%d",sizeof(x));
//}
struct animals
{
char dog; //1
unsigned long cat; //4(在Ubuntu环境下为8)
unsigned short pig; //2
char fox; //1
};
int main(){
struct animals x;
printf("%d",sizeof(x));
}
我们将上面的这段代码运行在32位和64位环境中会出现不同的结果,放在win和Ubuntu下也会出现不一样的结果,这是为什么呢?
首先我们要知道两个知识点:
1、32位系统同时处理的最大字节数为4字节,而64位系统能同时处理最大字节数为8字节;
2、win64中long类型的变量大小为4byte,Ubuntu下以64位编译,long类型的大小为8byte;
补充:32位系统下指针变量大小为4byte,64位系统下指针变量的大小为8byte;
cpu会采取字节对齐以及用空间换效率的方式存储数据
如上图所示:cpu为了提高运行效率,会用空间换时间,在放入一个char之后,只剩下3个字节的空间,不能够完整的放入一个int类型,那怎么办呢,现在有两种方案:
- 一种是先放入一部分的int,剩下的一个放在另外开辟的一块内存中,这样做空间利用率会得到提高,但cpu需要更多的步骤读取内存中的数据(假如cpu一次能读取4字节,第一次读到的是int的前三个字节,需要再读取一次才能将这个int全部读取完)。
- 另外一种是直接将完整的int类型放入新的内存,这样确实会浪费掉一部分空间,但却大大减少了cpu读取内存的步骤,有效的提升了数据操作的效率。
而我们的cup就是使用第二种方案,所以在分析内存的时候,不能简单的将所有变量类型与数量相乘再相加,还应当考虑到提高cup运算效率所采取的存放方式。
例如图中的xxxx结构体:
short a //2 char b //1 int c //4 char d //1 char e //1 double f //8 short g //2
若按照简单相加,那么只会占用19字节,这坑定是不对滴!
同时前面提到了32位系统与64位系统处理能力的不同,所以在不同的系统中,占用也不同,应当分开讨论:
32位:一次能处理4字节,所以我们将图中最大宽度设置为4方便分析。首先放入short,占2字节,剩2字节,能放入char,剩1字节,下一个变量为int,放不下,所以只能新开内存,将第二层放int,第三层放char,还剩3字节,再放一个char,剩下2字节,不够double的8字节,于是将第四层,第五层都放double,第六次放short。所以一共是4*6=24字节。但是第6层还剩下2字节,为啥不是占用22字节呢?
这是因为在xxxx这个结构体中,最大的类型为double,占用8字节,我们的内存应当与最大字节对齐,所以剩下的也算作被xxxx结构体占用了。对此我们可以对比yyy结构体,他占用的是6字节而不是8字节,就是由于yyy结构体的最大类型为short,占2字节,而无论是32,还是64都会剩下2字节,这个不会被占用。
还有一个细节,那就是为什么yyy中的short不能紧贴char放置呢?原因还是同上—应当与最大类型对齐!
练习题:
1、分析以下结构所占的存储空间大小:
struct animals
{
char dog;
unsigned long cat;
unsigned short pig;
char fox;
};
2、假设有以下说明和定义: 则语句 printf(“%d”, sizeof(struct creature)+sizeof(berry));的执行结果是?
typedef union
{
long i;
int k[5];
char c;
} fruit;
struct creature
{
short cat;
fruit apple;
double dog;
};
fruit berry;
答:T1:
T2: