当前位置: 首页 > news >正文

027 动静态库 —— 静态库

🦄 个人主页: 小米里的大麦-CSDN博客
🎏 所属专栏: Linux_小米里的大麦的博客-CSDN博客
🎁 GitHub主页: 小米里的大麦的 GitHub
⚙️ 操作环境: Visual Studio 2022

在这里插入图片描述

文章目录

    • 动静态库 —— 静态库
      • 1. 扩展概要(了解)
        • 1. 为什么说“4KB Page”是核心单位?
        • 2. 局部性原理?为什么和 4KB 页有关?
        • 3. 文件打开后是否每次都从磁盘读取?
        • 4. 每个打开的文件都会分配什么?
        • 5. Linux 如何管理所有内存?
        • 6. 操作系统能看到物理地址吗?
      • 2. 动静态库
        • 1. 库的制作者 如何制作静态库?
        • 2. 静态库 `demo`
          • 1. `My_static_library.h` (头文件)—— 对外接口声明
          • 2. `My_static_library.c`(源文件)—— 函数定义 + 错误处理
          • 3. `Makefile` 文件 —— 构建静态库的自动化脚本
        • 3. 库的使用者 如何使用静态库?
          • 1. 假设目录结构如下:
          • 2. test_main.c 示例:
      • 3. 总结:制作者 & 使用者视角速查表
    • 共勉

动静态库 —— 静态库

稀土掘金 | 动静态库的认识

CSDN | 理解文件系统|文件缓冲区|软硬链接|动静态库

CSDN | 相关好文

CSDN | 相关好文

1. 扩展概要(了解)

一个文件被打开操作系统要做什么:打开文件的流程 = 找 inode ➜ 创建 file 结构 ➜ 建立缓冲 ➜ 用页表映射读写 ➜ 后续 read/write 就操作 page 缓冲。

image-20250514202813281

1. 为什么说“4KB Page”是核心单位?

现代操作系统使用 分页机制(Paging) 管理内存,每一页(Page)是 一块固定大小的内存单元。Linux 默认:

  • 一页大小为 4KB
  • 物理内存也以页框为单位分配(如 Frame #0,Frame #1…)。
  • 所有虚拟内存地址映射到物理内存页框时,以 4KB 为基本单位。
地址空间页面大小含义
虚拟地址空间4KB/page每个进程有自己的虚拟地址空间
物理内存4KB/frame物理内存被划分为一个个页框
页面表(Page Table)将虚拟页映射到物理页框

所以:所有读写、分配、预加载、换页,都是以“页”为单位处理的!


2. 局部性原理?为什么和 4KB 页有关?

局部性原理包括:

  1. 时间局部性(Temporal Locality):刚访问的数据,可能马上还会用。
  2. 空间局部性(Spatial Locality):访问了地址 A,可能马上会访问 A 附近的数据。

为什么用 4KB?

  • 如果你访问了一个变量 a,操作系统会把 整个 4KB 页 都读进内存(或者缓存);
  • 这个 4KB 的空间里,很可能包含你接下来会访问的变量 b, c, d
  • 这样可以极大提升性能:只需要一次 IO,就加载一大片“可能用到的数据”。

磁盘文件(假设 8KB):[0~4KB] [4~8KB] (2 个块)

  • 内核发现 [0~4KB] 不在页缓存中。触发磁盘读取,加载整个 [0~4KB] 块到内存(即使只访问 1 字节)。存入页缓存,供后续快速访问。(访问第 1 字节 ➜ 内核页缓存判断没有 ➜ 从磁盘读 [0~4KB] ➜ 存入页缓存)
  • 继续访问第 3KB 字节 ➜ 命中页缓存 ➜ 直接返回([0~4KB] 已在页缓存中,直接返回数据(无需磁盘 IO)。)
  • 访问第 5KB 字节 ➜ 没有命中 ➜ 再从磁盘读 [4~8KB][4~8KB] 不在页缓存中,再次触发磁盘读取,加载整个 [4~8KB] 块到内存。)
问题回答
打开 1KB 文件会读取多少?最少读取 4KB
多出来 3KB 是什么?文件中后续的数据
是怎么加载的?从磁盘块读取并映射到页缓存
多出来的内容从哪加载?从磁盘上一次性读取 4KB 的块(block)加载进来
为什么这么设计?为了性能,利用局部性原理进行预读
如果文件只有 1KB 呢?剩下部分为空白,但页缓存仍然占用 4KB

3. 文件打开后是否每次都从磁盘读取?

不是!Linux 有一个机制叫做:页缓存(Page Cache)。把文件内容按“页”读取后,缓存到内存中。

  • 文件第一次打开时,会将所需部分 加载到内存页缓存(struct page)中
  • 之后对文件的 readwrite 操作,都直接在内存中进行,不再频繁访问磁盘。

4. 每个打开的文件都会分配什么?
对象含义
struct file表示这次“打开”
struct inode表示文件的“元数据”(公共)
页缓存(Page)对应的文件内容存到内存的页中
缓冲区(Buffer)应用层的输入输出缓冲区

所以:每个打开的文件,不管在哪个进程中,都有自己的“打开实例”,但共享 inode 和缓存页。


5. Linux 如何管理所有内存?

Linux 会维护一个大的 mem_map[] 数组,里面是所有 物理内存页的描述结构 struct page

  • 每当程序申请内存,都会通过虚拟地址查找页表,映射到 mem_map[i] 对应的页框。
  • mem_map[i] 就表示第 i 个物理页框的属性(是否空闲、是否缓存文件、是否在使用等)。

6. 操作系统能看到物理地址吗?

操作系统自己可以看见物理地址,但应用程序不行。

  • 每个进程只能访问自己的 虚拟地址空间
  • 操作系统通过 页表机制 管理虚拟地址 → 物理地址的映射;

所以现代操作系统的内存与文件缓存管理,都是基于“4KB 页”为单位,结合“局部性原理”和“分页机制”来提高性能和效率。

image-20250514204626090


2. 动静态库

1. 库的制作者 如何制作静态库?

步骤如下:

  • ① 编写 .c 实现和 .h 头文件:对外接口声明和函数的实现。

  • ② 使用 gcc -c 编译为目标文件(.o):gcc -c MyStaticLibrary.c -o MyStaticLibrary.o

  • ③ 使用 ar 命令打包创建静态库 .aar -rc My_static_library.a My_static_library.o

  • ④ 组织输出目录(可选):

mkdir -p lib/include lib/My_static_library_lib
cp *.h lib/include/
cp *.a lib/My_static_library_lib/
2. 静态库 demo
1. My_static_library.h (头文件)—— 对外接口声明
#pragma once                    // 防止头文件被重复包含
#include <stdio.h>             // 引入标准库(虽然这个例子中不一定需要)extern int myerrno;            // 声明一个全局变量,用于错误码(比如除0错误)// 函数声明:提供加、减、乘、除功能
int add(int x, int y);         // 加法
int sub(int x, int y);         // 减法
int mul(int x, int y);         // 乘法
int div(int x, int y);         // 除法(除数为0时返回-1,并设置myerrno=1)
2. My_static_library.c(源文件)—— 函数定义 + 错误处理
#include "My_static_library.h"int myerrno = 0;               // 定义全局错误码变量int add(int x, int y)
{return x + y;
}int sub(int x, int y)
{return x - y;
}int mul(int x, int y)
{return x * y;
}int div(int x, int y)
{if (y == 0)                // 检查除数是否为0{myerrno = 1;           // 设置错误码return -1;             // 返回错误标识}return x / y;
}
3. Makefile 文件 —— 构建静态库的自动化脚本
# 目标静态库名称
lib = My_static_library.a# 构建静态库目标:由目标文件构建 .a 文件
$(lib): My_static_library.oar -rc $@ $^# 生成 .o 目标文件
My_static_library.o: My_static_library.cgcc -c $^# 清理构建产物
.PHONY: clean
clean:rm -rf *.o *.a lib# 输出头文件和库文件到标准目录
.PHONY: output
output:mkdir -p lib/include                        # 创建头文件目录mkdir -p lib/My_static_library_lib          # 创建库文件目录cp *.h lib/include                          # 复制头文件cp *.a lib/My_static_library_lib  	        # 复制静态库文件

3. 库的使用者 如何使用静态库?
1. 假设目录结构如下:
.
├── lib
│   ├── include
│   │   └── My_static_library.h
│   └── My_static_library_lib
│       └── My_static_library.a
├── makefile
├── My_static_library.a
├── My_static_library.c
├── My_static_library.h
├── My_static_library.o
└── test_main.c

image-20250520203807988

2. test_main.c 示例:
#include <stdio.h>
#include "My_static_library.h"  // 包含头文件int main()
{printf("add(3, 4) = %d\n", add(3, 4));printf("div(10, 0) = %d\n", div(10, 0));if (myerrno == 1){printf("Error: Divide by zero\n");}return 0;
}

编译命令说明:

gcc -o test test_main.c -I.lib/include -L./lib/My_static_library_lib -l:My_static_library.a
选项作用说明
-I.lib/include指定头文件搜索路径确保 My_static_library.h 能被 #include 找到
-L./lib/My_static_library_lib指定库文件搜索路径. 表示当前目录(即 ./My_static_library.a
-l:My_static_library.a直接链接指定的 .a 文件: 表示精确匹配文件名,直接指定库文件名,而非默认的 libxxx.a 格式

image-20250520205029824

小技巧(调试辅助):

  • 查看 .a 文件里的内容:

    ar -t My_static_library.a
    
  • 若静态库升级,记得重新编译目标文件和链接。


3. 总结:制作者 & 使用者视角速查表

角色步骤命令或说明
制作者编写 Header/SourceMy_static_library.h/My_static_library.c
生成目标文件(.o)gcc -c My_static_library.c -o My_static_library.o
打包静态库(.a)ar -rc My_static_library.a My_static_library.o
分发库与头文件mkdir -p lib/include lib/lib && cp *.h lib/include/ && cp *.a lib/lib/
使用者包含头文件 (include)#include "My_static_library.h"
编译链接形成可执行程序gcc -o test test_main.c -I.lib/include -L./lib/My_static_library_lib -l:My_static_library.a

共勉

在这里插入图片描述
在这里插入图片描述

http://www.dtcms.com/a/334359.html

相关文章:

  • Docker数据卷挂载和本地目录挂载
  • 八、SpringBoot项目热部署
  • Java服务自动停止原因及查找方法
  • Cloudflare Tunnels 部署与隧道异常关闭的解决方案
  • 攻击者如何毒害人工智能工具和防御系统
  • 【更新公告】C++算法·线段树
  • CF每日3题(1500-1700)
  • 《WINDOWS 环境下32位汇编语言程序设计》第2章 准备编程环境
  • IO流-序列化流
  • 记录 GMS 认证相关条件
  • 玄机靶场 | 日志分析-Tomcat日志分析
  • AI生成视频开源模型技术解析
  • Rocky Linux 9.2:从 /home 分区释放 10G 空间扩容到 / 根分区
  • AI可行性分析:数据×算法×反馈=成功
  • 【P40 6-3】OpenCV Python——图像融合(两张相同属性的图片按比例叠加),addWeighted()
  • 软考 系统架构设计师系列知识点之杂项集萃(124)
  • 池式结构之连接池
  • pwn定时器,ARM定时delay 外部中断用函数指针(统一)day55,56
  • 数据结构:满二叉树 (Full Binary Tree) 和 完全二叉树 (Complete Binary Tree)
  • 安卓定制开机动画的bootanimation.zip的注意点
  • (论文阅读)FedViT:边缘视觉转换器的联邦持续学习
  • 美国服务器环境下Windows容器工作负载基于指标的自动扩缩
  • Java驾驭金融风暴:大数据+机器学习重塑资产配置与风险平衡
  • CPP多线程3:async和future、promise
  • 【八股】计网-计算机网络-秋招
  • 让数据库交互更优雅:MyBatis核心机制深度解析(附实战视频教程)
  • 【DL学习笔记】常用数据集总结
  • 详解flink java基础(二)
  • 使用nvm查看/安装node版本
  • Spring AI 进阶之路01:三步将 AI 整合进 Spring Boot