mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
1304 字
3 分钟
c03
2025-11-13
c

inline 内敛函数#

在调用者内部直接复制展开内敛函数代码,类似 #define 宏展开,目的是减少函数调用的开销,但是这只是针对于编译器的建议,最后是否内敛取决于编译器,如果认为函数不复杂,能在调用点展开,才会真正内敛

static 关键字#

使函数具有内部链接属性,只能定义他的源文件内的访问

static void helper_function(void)
{
...
}
void public_function(void)
{
helper_function();
}

特点:

  • 文件作用域
  • 避免作用域
  • 促进优化

inline & static 联合使用#

作用:即建议内敛展开,又限制作用域到当前文件

指针#

指针在x86 中占4个字节 , x64占8个字节

  • 指针是一个变量
  • 他存放内存的地址
  • 明确这个内存的宽度

指针的初始化,可以让指针指向某个变量的地址也可以让指针指向一个分配的内存或者字符串常量,或者unllptr/NULL, 但是要尽量避免野指针

void *p#

  • 可以接受任何类型的指针,其他指针隐式转化成这个类型,不能*p来取值,先转成特定类型再取值
  • 赋值给其他类型的指针需要强转
  • 不能进行解引用 *p 运算,必须转换

字符指针#

字符执政既可以指向字符又可以指向字符串,及字符串首字符的地址,

二级指针#

二级指针存放的是一级指针的地址,一级指针存放的是普通变量的地址

int a = 10;
int *p = &a;
int **pp = &p;

内存分配#

系统虚拟空间的内存空间布局#

a

程序内存布局#

内存分类#

  • 堆heap malloc/free 地址由低到高
  • 栈stack 由系统自动分别配与与回收 增长由高到低
  • 代码区
  • 静态区

堆和栈的区别#

名称内存分类大小限制效率比较存放内容
由系统自动分配与回收,增长由高到低1M~10M,内核层12k-24k不等系统自动分配速度较快。但是程序员无法控制用来记录程序执行时函数调用过程中的活动记录(栈帧)参数 返回地址 ebp, 局部变量等等
malloc/free,地址由低到高受限于计算机系统中的有效虚拟内存速度较慢,而且容易产生内存碎片一般实在对的头部用一个字节存放堆的大小,剩余部分由程序员计算的需要决定

内存地址分类和寻址模式#

  • 逻辑地址: 逻辑地址是 编译器生成的,使用C语言指针的时候,指针的值就是逻辑地址。对于每一个进程而言,他们都有一样的进程地址和空间,类似的逻辑地址,甚至可能相同。逻辑地址由段地址+段内偏移组成
  • 线性地址:是由分段机制将逻辑地址转化而来,如果没有分段机制作用,那么程序的逻辑地址就是线性地址了
  • 物理地址: 是CPU在存取数据时最终在地址总线上发出的电平信号,靠该地址访问对应数据。要得到窝里地址,必须要将逻辑地址经过分段,分页等级制转化而来

从逻辑地址到物理地址的翻译叫寻址.x86体系结构下,使用较多的内存寻址模型主要有两种:

  1. 实模式分段模型
    • 16位寄存器(64k),20位地址(1M)
    • 每个段64KB,共16个段
    • cs/ds 寄存的是段的起始地址(末尾4位为0,可不存,相当于 seg>>4)
    • ip 等寄存器中放段偏移
    • 逻辑地址到物理地址 seg << 4 + offest
  2. 保护式扁平模型
    • 32/64位寄存器,32/64位地址
    • 1个寄存器就可以寻址整个线性性地址空间 cs/ds寄存器值固定为0或者定值,无需参与地址计算逻辑地址到物理地址:页表

b

程序内存分配#

int g_iNum = 10; // 全局变量在静态区
int main(void)
{
int a = 127; // 局部变量在栈上
char buf[128];
char* p = (char*)malloc(256); // 申请分配内存,在堆上
if(p == NULL)
{ return -1; }
memset(p, 0, 256);
free(p);
p = NULL;
return 0;
}

内存泄露:#

在申请内存后没有及时释放#

  1. 平凡的内存泄露将最终耗尽整个内存的资源,让系统的性能大幅度下降。

API不正确调用导致的内存泄露#

  1. 比如Windows API 中的CreateThead 函数 等
  2. 打开的句柄没有关闭

结构体#

结构体的定义和使用#

// #1
struct s_name
{
...
};
struct s_name Astruct; // 这种定义方式需要使用这这种定义方式,否则在编译时某些编译器会直接报错
// #2
struct s_name
{
...
} structA, structB; // 造在定义的时候已经声明了几个变量
// 或者
struct
{
...
} structA, structB; // 临时定义
// #3 最常用的命名方式
typedef struct _s_name
{
...
} s_name, *ps_name;
s_name structA;

结构体可能的内存分布 (使用malloc 创建)#

c

浅拷贝和深拷贝#

  1. 浅拷贝:只是复制了目标的地址
  2. 深拷贝:完全复制了目标

计算结构体大小#

  1. 自然对齐:在默认情况下各成员变量存放的起始地址相对于结构的起始位置的偏移量(基本类型)或其倍数如果该成员为非基本成员,则为其子成员中最大基本类型的整数倍
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

c03
https://yoyolp.github.io/posts/c_asm/c03/
作者
超级玉米人
发布于
2025-11-13
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录