有人给对齐原则做过总结,具体在哪里看到现在已记不起来,这里引用一下前人的经验(在没有#pragma pack宏的情况下):
原则1、数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。
原则2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)
原则3、收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
这三个原则具体怎样理解呢?我们看下面几个例子,通过实例来加深理解。
例1:struct {
short a1;
short a2;
short a3;
}A;
struct{
long a1;
short a2;
}B;
sizeof(A) = 6; 这个很好理解,三个short都为2。
sizeof(B) = 8; 这个比是不是比预想的大2个字节?long为4,short为2,整个为8,因为原则3。
例2:struct A{
int a;
char b;
short c;
};
struct B{
char b;
int a;
short c;
};
sizeof(A) = 8; int为4,char为1,short为2,这里用到了原则1和原则3。
sizeof(B) = 12; 是否超出预想范围?char为1,int为4,short为2,怎么会是12?还是原则1和原则3。
深究一下,为什么是这样,我们可以看看内存里的布局情况。
a b c
A的内存布局:1111, 1*, 11
b a c
B的内存布局:1***, 1111, 11**
其中星号*表示填充的字节。A中,b后面为何要补充一个字节?因为c为short,其起始位置要为2的倍数,就是原则1。c的后面没有补充,因为b和c正好占用4个字节,整个A占用空间为4的倍数,也就是最大成员int类型的倍数,所以不用补充。
B中,b是char为1,b后面补充了3个字节,因为a是int为4,根据原则1,起始位置要为4的倍数,所以b后面要补充3个字节。c后面补充两个字节,根据原则3,整个B占用空间要为4的倍数,c后面不补充,整个B的空间为10,不符,所以要补充2个字节。
再看一个结构中含有结构成员的例子:
例3:struct A{
int a;
double b;
float c;
};
struct B{
char e[2];
int f;
double g;
short h;
struct A i;
};
sizeof(A) = 24; 这个比较好理解,int为4,double为8,float为4,总长为8的倍数,补齐,所以整个A为24。
sizeof(B) = 48; 看看B的内存布局。
e f g h i
B的内存布局:11* *, 1111, 11111111, 11 * * * * * *, 1111* * * *, 11111111, 1111 * * * *
i其实就是A的内存布局。i的起始位置要为8的倍数,所以h后面要补齐。把B的内存布局弄清楚,有关结构体的对齐方式基本就算掌握了。
分享到:
相关推荐
在C语言中,动态内存分配是一项重要的编程技巧,它允许程序员在程序运行时根据需要分配内存,而不是在编译时预设固定的内存空间。本文将深入解析动态内存分配的细节和一个简单的C语言程序示例。 C语言提供了四个与...
`realloc()`则用于改变已分配内存的大小,可以增大或减小空间。 2. **内存创建(分配)**: 使用`malloc()`函数时,我们需要提供所需内存的字节数。例如,要分配一个整型数组,我们可以写`int *arr = (int*) ...
此外,还可以使用`calloc`一次性分配零初始化的内存,以及`realloc`调整已分配内存的大小。在C++中,`new`和`delete`是对应的动态内存管理操作,它们的行为类似于`malloc`和`free`。 在实际编程中,理解这些内存...
1. **静态内存分配**:在程序开始执行时,操作系统为全局变量和静态变量分配内存。这部分内存存在于数据段和BSS段。BSS段存储未初始化的全局和静态变量,而数据段则存储已初始化的变量。 2. **动态内存分配**:在...
本文主要探讨了两个用于动态分配内存空间的函数:malloc() 和 calloc()。 malloc() 函数是C语言中用于动态内存分配的基本工具。它允许程序在运行时根据需要请求任意大小的内存块。`malloc()` 函数的声明如下: ```...
它涉及到如何在运行时为变量和对象分配内存,以及何时和如何释放这些内存。本篇文章将深入探讨C语言的内存分配,特别是动态内存分配,以及与之相关的堆内存分配。 动态内存分配在程序执行期间提供了一种灵活的方式...
1. 用malloc动态分配内存后一定要判断一下分配是否成功,判断指针的值是否为NULL。 2. 内存分配成功后要对内存单元进行初始化。 3. 内存分配成功且初始化后使用时别越界了。 4. 内存使用完后要用free(p)释放,注意,...
这种机制允许程序员在需要时动态地分配内存空间,以满足程序的需求。 动态内存分配的基础 在C语言中,动态内存分配是通过malloc函数实现的。malloc函数的原型为void *malloc(size_t n),其中n是要分配的内存的大小...
C语言动态内存分配是指在程序运行时分配内存空间,以满足程序的需求。在某些情况下,程序需要在运行时动态地分配内存,以便存储大量数据或处理不确定大小的数据。例如,在顺序对一批文件进行解析时,文件的大小是...
而堆上的内存空间较大,分配和回收需要程序员自己控制,通常比栈上的内存分配和回收速度要慢。 在Windows操作系统中,还可以使用VirtualAlloc()和VirtualFree()等API进行内存的分配和释放,这些API提供了更底层的...
本实验主要是模拟在分页式管理方式下用位视图来表示内存分配情况,实现主存空间的分配和回收。用一个8*8矩阵表示内存的占用状态,1表示已经占用,0表示未占用要求输入作业名字和所需内存块。
- **分配内存**:当需要分配内存时,从内存池中找到合适的空闲块,更新内存池状态并返回内存块。 - **释放内存**:释放内存时,并不直接归还给系统,而是将其标记为可用状态,放入空闲块链表。 - **内存碎片控制*...
堆则是动态分配内存的地方,程序员可以通过malloc、calloc、realloc和free等函数进行手动管理,灵活性高但效率相对较低。静态存储区用于存储全局变量和静态变量,这些变量在整个程序生命周期内都存在。 1. **栈内存...
共用体的大小取决于最长的成员所占用的内存空间。 例如: ```c union data { int i; char ch; float f; } X1; ``` 在这个例子中,`X1`共用体的最大成员是`float`类型,占用4个字节。因此,整个共用体也占用4个...
为了高效利用内存资源,操作系统通常会采用一定的算法来决定如何为进程分配内存空间。其中,“最优适应”(Best Fit)算法是一种常用的策略,它寻找所有足够大的空闲分区中的最小的一个进行分配,从而尽可能减少内存...
- **堆区**:用于动态分配的内存空间,由程序员手动分配和释放。 - **常量区**:用于存储字符串常量等不可修改的数据。 #### 二、C语言变量分配与5个区的概念 C语言中的变量根据其存储方式可以分为以下几类: 1. ...
3. `realloc()`:调整已分配内存块的大小,可以增大或缩小内存空间。需要注意的是,如果内存无法扩展,`realloc()`可能会返回一个新分配的内存地址,原有内存将不再有效。 4. `free()`:释放由`malloc()`, `calloc()...
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。 2.5 堆和栈中的存储内容 栈:在函数调用时...
### C语言内存分配详解 #### 一、野指针的概念及其管理 野指针是指一个指针指向了一个...通过初始化指针为`NULL`、合理分配内存空间以及在函数入口处进行校验等手段,可以有效减少内存错误的发生,提高程序的健壮性。
C语言动态分配内存详解 C语言动态分配内存是一种高级内存管理技术,它允许程序员在运行时动态地分配和释放内存,使得程序更加灵活和高效。本文将详细介绍C语言动态分配内存的原理、使用方法和注意事项。 一、什么...