1、首先我们要知道一些变量所占据的内存有多少和字节的换算单位。
(1)1B(字节)= 8位(比特)
(2)1KB(千字节)= 1024(2^9)B(字节)
(3)1MB(兆字节)= 1024KB(千字节)
(4)1GB(吉字节)= 1024MB(兆字节)
(5)1TB(太字节) = 1024GB(吉字节)
2、C语言中变量所占据的内存。
#include <stdio.h>
int main()
{
printf("int=%d\n", sizeof(int));
printf("short=%d\n", sizeof(short));
printf("char=%d\n", sizeof(char));
printf("float=%d\n", sizeof(float));
printf("double=%d\n", sizeof(double));
printf("int *=%d\n", sizeof(int*));
printf("char *=%d\n", sizeof(char*));
printf("float *=%d\n", sizeof(float*));
printf("double *%d\n", sizeof(double*));
return 0;
}

我们知道每个变量和它所占的内存后,我们就可以更好的去定义结构体了,首先明确结构体定义的原则:
必须保证结构体字节对齐(两个对齐)。
(1)保证最长字节对齐
(2)保证整数倍地址对齐
例1
#include <stdio.h>
int main()
{
typedef struct Student
{
int a;
char c;
}Student;
printf("%d", sizeof(Student));
return 0;
}
如果你不了解结构体的内存分配,你大概率会猜此结构体占内存为5个字节,正确答案:输出结果为8字节,一个整型加一个字符型变量,正常运算的确是5个字节,但是在结构体中存储方式是不同的,如图,在地址空间中a和c是并列的,结构体中也是挨着的,原则中,必须保证最长字节对齐,所以有3个字节是被浪费掉的,总体占据8个字节。
| a | |||
| c | x | x | x |
例2
#include <stdio.h>
int main()
{
typedef struct Student
{
char a;
int b;
char c;
}Student;
printf("%d", sizeof(Student));
return 0;
}
一个字符型,两个整型变量,在结构体中要保证最长字节对齐,所以此结构体输出为12字节,空间内存分配如图
| a | x | x | x |
| b | |||
| c | x | x | x |
如图,最长字节对齐,所以每个变量占据4个字节,但是有6字节的空间是被浪费掉的,b的地址在a的后面,c的地址在b的后面,地址是从小到大排列的。
例2改进
#include <stdio.h>
int main()
{
typedef struct Student
{
int a;
char b;
char c;
}Student;
printf("%d", sizeof(Student));
return 0;
}
如图,输出结果为8字节,三个变量和例1的两个变量内存空间占据相同,空间中内存分配如图:
| a | |||
| b | c | x | x |
最开始的原则中第二条我们说过保证整数倍地址对齐,最后两个字节被浪费,存储的8个位置我们给它地址进行编号,如图储存的变量位置必须是内存的整数倍,也就是说,如果两个占4字节的变量存储,那么都会被占满,或者是四个占2字节的变量,可以完全占用。
| 0 | 1 | 2 | 3 |
| 4 | 5 | 6 | 7 |
例3
#include <stdio.h>
int main()
{
typedef struct Student {
int a;
short b;
char c;
char d;
}Student;
printf("%d", sizeof(Student));
return 0;
}
结构体中是定义了一个整型,一个短整型,两个字符型变量,以最长的int为标准,可以知道,地址空间中内存长度为4,整体占据内存为8字节。如图:内存没有被浪费。
| a | |||
| b | c | c | |
例4
#include <stdio.h>
int main()
{
typedef struct Student {
int a;
char b;
short c;
char d;
}Student;
printf("%d", sizeof(Student));
return 0;
}
结构体中定义了一个整型,一个短整型,两个字符型变量,定义的数量相同,但是因为地址空间的位置不同,它所占据的内存也不是和例3一样的8字节,它是12字节。如图:
| a | |||
| b | x | c | |
| d | x | x | x |
最长的整型变量a占据4个字节,按照原则2,保证整数倍地址对齐,c占两个字节,所以c的位置应该是2的整数倍如果对其进行编号,c的起始地址在6位置,d的位置在c后面,以此类推。
| 0 | 1 | 2 | 3 |
| 4 | 5 | 6 | 7 |
例5
#include <stdio.h>
int main()
{
typedef struct Student {
int a;
long long int b;
short c;
int d;
char e;
}Student;
printf("%d", sizeof(Student));
return 0;
}
long long int 占据内存为8,计算此结构体所占内存为32字节,可以看到,每一行的地址空间最多8字节,第一行a,b地址在a后面,但是占据8个字节,所以第二行b,占据整行,然后第三行c占据2字节,2字节后面,是d占据4字节,最后一行e占1字节,空了七个字节。如图:
| a | x | x | x | x | |||
| b | |||||||
| c | x | x | d | ||||
| e | x | x | x | x | x | x | x |
那么,如何分配才能让它更好利用内存呢?内存为24字节。
| a | |||||||
| b | c | ||||||
| c | e | x | x | x | x | x | |
程序如下:
#include <stdio.h>
int main()
{
typedef struct Student {
long long int a;
int b;
int c;
short d;
char e;
}Student;
printf("%d", sizeof(Student));
return 0;
}
例6
#include <stdio.h>
int main()
{
typedef struct Student {
char a : 2;
char b : 2;
char c : 2;
char d : 2;
}Student;
printf("%d", sizeof(Student));
return 0;
}
我们定义了4个字符型变量但是这种表示方法,是在硬件编程中常用的,尤其汇编语言中,这四个变量总计占1个字节,8位(看本文开头),a : 2 定义的是两位,占两个比特。
| a | b | c | d |
字符型变量2字节,16位,本结构体中总计1个字节。
本文通过多个实例详细解析了C语言中结构体的内存分配原则,包括最长字节对齐和整数倍地址对齐,展示了如何合理布局结构体成员以减少内存浪费。

7387

被折叠的 条评论
为什么被折叠?



