大小端
- 大端:高字节存放在低地址,主要用于网络协议(IP, TCP, UDP)
- 小端:低字节存放在低地址,主要用于X86, ARM
// 判断大小端
uint32_t word = 0xAABBCCDD;
char* p = (char*) (&word);
for(int i=0; i<4; ++i){
printf("byte[%d]=0x%02x ", i, (unsigned int)*(p+i));
}
// 大端结果:AA BB CC DD
// 小端结果:DD CC BB AA
内存分配
参考这篇博客里的解释,内存通常可分为如下几块:
BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化,或初始化为0的全局变量,静态局部变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。
数据段:数据段(data segment)通常是指用来存放程序中已初始化为非0的全局变量的一块内存区域。数据段属于静态内存分配。
代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)
栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
从上图可以看出,栈优先分配高地址,然后往低地址走;堆优先分配低地址,然后往高地址走。另外,在为结构体数据分配内存时,先为结构体数据分配一片内存空间,此时较低地址为结构体数据的入口,然后从低地址到高地址按结构体数据成员定义顺序依次分配内存空间。例如:
typedef struct{
char a;
char b;
char c;
int d;
} T1;
结构体成员按定义的顺序其存储地址依次增长
字符串相关内存分配
- 参考:http://t.csdn.cn/XXXJq
- 静态存储区的数据(全局区)整个程序运行期间存在,可以通过地址访问内存。
- 堆和栈上分配的数据,一旦数据销毁,就无法通过地址访问,运行时崩溃。
- 数据段(BSS段、DATA段)、代码段(.RODATA)、堆栈段的区别
char* p1 = "hello"; // "hello"为常量字符串,只读(rodata段),内存分配在静态存储区
const char* p2 = "hello"; // 同上,只读常量字符串在内存中只会存在一份内存
static char* p3 = "hello"; // 字符串内存分配在 data 段
char str1[] = "hello"; // str1 在栈上分配数组内存, 内存数据可变
const char str2[] = "hello"; // str2 在栈上分配内存,内存数据不可变
内存对齐
为什么要内存对齐/内存对齐的作用
- 平台原因(移植原因):不是所有硬件平台都能访问任意地址上的任意数据。
- 硬件原因:提升CPU内存访问速度
- CPU是按块读取内存的,比如一次性读取4个字节,比如要读取一个4字节大小的数据,若数据从1字节开始,则需要先读0-3字节,再读4-7字节,再去掉0字节和4-7字节。
参考文献:
为什么要进行结构体内存对齐
内存对齐是什么
内存对齐规则
- 原则1、数据成员对齐规则:结构体或联合体的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始
- 原则2、结构体作为成员:如果一个结构体包含结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。
- 原则3、整体大小:结构体的总大小,必须是内部最大成员的整数倍,不足要补齐。对齐将按照 #pragram pack 指定的数值和结构或者联合体最大数据成员长度中比较小的那个 ,也就是 min(#pragram pack() , 长度最长的数据成员);
- 原则4、#pragram pack(n) 设置n字节对齐,vc6默认8,
经验:将结构体中数据类型大的成员往后放可以节省空间
参考文献: