C的秘密(二)

1.内存对齐【#program pack】

理论上,处理器可以访问寻址处理任意地址的字节,但实际上为了保证计算机读取数据的高效性,CPU通过地址总线来访问内存。以32位处理器为例,一般来说寻址步长为32位(4个字节),也就是每次从内存读取4个字节。为了提高存取效率,一般来说编译器会自动将一个数据尽量放在一个步长之内,避免跨步长存储,称为内存对齐。

​ 每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。可通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

#pragma pack(1)    /*将对齐位数强制定位1*/
struct node{
    
    
  char f_1byte;
  int e_4byte;
  short int a_2byte;
  char b_1byte;
};
struct node n;
printf("%d\n",sizeof(n)); /*输出结果10*/

2.内存分配

​ 程序运行过程中(进程)的地址空间,代码区、常量区、全局数据区的内存在程序启动时就由操作系统已分配好(大小固定),不能由用户分配和释放(由OS),这就是静态内存分配。

​ 关于动态内存分配(栈区和堆区),根据实际需求来分配和释放,不用在程序刚启动时就备足空间。关于栈区和堆区的区别如下:

  • 栈区由系统动态分配和释放(一般来说,程序启动时会为栈区分配一块大小适当的内存,对于一般函数来说已经足够了,当函数出现较大的局部变量的时候,编译器就会在函数代码中插入针对栈的动态内存分配函数)
  • 堆区由用户分配和释放(堆Heap是唯一由程序员控制的内存区域

3.整数在内存中实际的存储方式?

​ 为了方便硬件底层更好的处理运算(最基本的运算就是加减法),整数实际存储在内存中的二进制形式为补码方式。

​ 正数的原码、反码、补码都是一样的。负数的反码为负数原码中除符号首位外所有位取反,负数的补码在负数的反码基础上+1。

​ 利用补码可以将减法优化成为加法【a-b 等价于 a+(-b)】,提高硬件的运算效率

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/caq_jw/article/details/111736180