From 9bdb691602f08b65882d01e03125950dc0125340 Mon Sep 17 00:00:00 2001 From: e2hang <2099307493@qq.com> Date: Sun, 28 Dec 2025 16:11:38 +0800 Subject: [PATCH] A Example for DLLs --- C/Compiler/readme.md | 376 ++++++++++++++++++++++ DynamicLinkLibrary/my_str-dll/libmy_str.a | Bin 0 -> 1512 bytes DynamicLinkLibrary/my_str-dll/main.c | 21 ++ DynamicLinkLibrary/my_str-dll/main.exe | Bin 0 -> 80438 bytes DynamicLinkLibrary/my_str-dll/my_str.c | 110 +++++++ DynamicLinkLibrary/my_str-dll/my_str.dll | Bin 0 -> 72410 bytes DynamicLinkLibrary/my_str-dll/my_str.h | 17 + DynamicLinkLibrary/readme.md | 326 +++++++++++++++++++ 8 files changed, 850 insertions(+) create mode 100644 C/Compiler/readme.md create mode 100644 DynamicLinkLibrary/my_str-dll/libmy_str.a create mode 100644 DynamicLinkLibrary/my_str-dll/main.c create mode 100644 DynamicLinkLibrary/my_str-dll/main.exe create mode 100644 DynamicLinkLibrary/my_str-dll/my_str.c create mode 100644 DynamicLinkLibrary/my_str-dll/my_str.dll create mode 100644 DynamicLinkLibrary/my_str-dll/my_str.h create mode 100644 DynamicLinkLibrary/readme.md diff --git a/C/Compiler/readme.md b/C/Compiler/readme.md new file mode 100644 index 0000000..9d63f40 --- /dev/null +++ b/C/Compiler/readme.md @@ -0,0 +1,376 @@ +### 1. GCC 常用指令大表 + +| 指令 | 全称/含义 | 作用说明 | +| --- | --- | --- | +| **`-c`** | Compile | 只编译生成目标文件 (`.o`),**不进行链接**。 | +| **`-o `** | Output | 指定输出文件的名称(可执行文件、库文件等)。 | +| **`-g`** | Debug | 生成调试信息,方便使用 `gdb` 进行断点调试。 | +| **`-O0/1/2/3`** | Optimize | 设置优化等级。`-O2` 是最常用的平衡选项,`-O3` 追求极致速度。 | +| **`-I `** | Include | 添加**头文件**搜索路径。 | +| **`-L `** | Library Path | 添加**库文件**搜索路径。 | +| **`-l `** | link library | 链接具体的库(如 `-lm` 链接 `libmath`)。 | +| **`-D `** | Define | 定义宏(等同于代码里的 `#define`)。 | +| **`-Wall`** | Warnings all | 开启几乎所有的常用警告,强烈建议永远加上。 | +| **`-fPIC`** | Position Independent Code | 生成位置无关代码,**制作 `.so` 动态库必带**。 | +| **`-shared`** | Shared | 告诉编译器生成一个动态链接库。 | +| **`-std=c++17`** | Standard | 指定使用的 C++ 标准版本(如 c++11, c++14, c++20)。 | + +--- + +### 2. 什么是 `-Wl`? + +**`-Wl` (Warn linker)** 的意思是:**“喂,GCC,把后面跟着的参数直接传给底层的链接器(ld)。”** + +因为 GCC 本身只是一个“前端”驱动程序,它负责调用预处理器、编译器、汇编器和链接器。有时候你需要设置一些链接器特有的高级选项,而 GCC 并不直接支持这些选项。 + +* **格式**:`-Wl,,` +* **注意**:参数之间是用**逗号**隔开的,不能有空格。 + +--- + +### 3. 为什么有 `--out-implib,xxx.a`? + +这通常出现在 **Windows (MinGW)** 环境下开发 DLL 时。这是一个非常关键的概念:**“导入库” (Import Library)**。 + +#### 为什么需要它? + +在 Windows 上,如果你编译了一个 `my.dll`,主程序运行的时候需要它,但**编译主程序的时候**,链接器也需要知道这个 DLL 里到底有哪些函数。 + +* **`.dll`**:是运行时用的(包含代码逻辑)。 +* **`.a` 或 `.lib` (导入库)**:是编译链接时用的(包含函数地址列表)。 + +#### 指令解析: + +`g++ -shared -o my.dll -Wl,--out-implib,libmy.dll.a` + +1. **`-shared -o my.dll`**:生成动态链接库主体。 +2. **`-Wl,`**:接下来的参数是给链接器看的。 +3. **`--out-implib,libmy.dll.a`**:链接器,请帮我顺便生成一个名为 `libmy.dll.a` 的**导入库**。 + +**这样做的流程是:** + +* **第一步**:你编译 DLL,得到了 `my.dll` 和 `libmy.dll.a`。 +* **第二步**:你编译主程序,链接 `libmy.dll.a`(使用 `-L. -lmy`)。 +* **第三步**:运行程序,Windows 会根据之前链接的信息去加载 `my.dll`。 + +--- + +### 4. 总结:`-Wl` 后的常用参数 + +除了 `--out-implib`,你可能还会见到这些: + +* **`-Wl,-rpath,`**:指定运行时查找 `.so` 的路径(Linux 常用,解决找不到库的问题)。 +* **`-Wl,--stack,`**:设置程序栈的大小。 +* **`-Wl,--as-needed`**:只链接那些代码中真正用到的库,减小体积。 + +> **小贴士**:如果你在 Linux 下开发,通常不需要 `--out-implib`,因为 Linux 的 `.so` 文件既是运行时库,也可以直接作为链接时的导入信息。 + +你现在是在尝试把现有的 C++ 库打包成 DLL 给其他语言(比如 Python 或 Java)调用吗?如果是的话,我们可以聊聊 `extern "C"` 的深层必要性。 + +--- + +哈哈,这正是 C/C++ 的“黑魔法”所在:它是现代编程世界的**基石**。 + +不管是 Python 的 `numpy`、Node.js 的原生模块,还是 Android (Java/Kotlin) 的底层驱动,核心全是这么干的。这种技术统称为 **FFI (Foreign Function Interface,外部函数接口)**。 + +要实现这个,主要靠这两根支柱: + +--- + +### 1. 核心秘诀:`extern "C"` + +这是最关键的一步。 + +C++ 支持**函数重载**,所以编译器会偷偷修改函数名(这叫 **Name Mangling**)。比如 `add(int, int)` 在 C++ 内部可能变成了 `_Z3addii`。 +其他语言(比如 Python)去 DLL 里找 `add` 时,根本找不到这个怪名字。 + +**解决方法:** +在 C++ 头文件里加上 `extern "C"`,告诉编译器:“请按 C 语言那种简单粗暴的方式命名,叫 `add` 就给我留成 `add`。” + +```cpp +// mylib.h +extern "C" { + __declspec(dllexport) int add(int a, int b) { + return a + b; + } +} + +``` + +--- + +### 2. 不同语言是怎么“吃”掉这个库的? + +我给你举两个最常用的例子: + +#### A. Python 调用(最简单) + +Python 有个内置库叫 `ctypes`,专门用来“白嫖” C 库。 + +```python +import ctypes + +# 1. 加载库 +# Windows 用 .dll, Linux 用 .so +lib = ctypes.CDLL("./mylib.dll") + +# 2. 直接调用 +result = lib.add(10, 20) +print(f"结果是: {result}") + +``` + +#### B. Java 调用 (JNI) + +Java 稍微复杂点,它需要一个“中介”。 + +1. 在 Java 里写个 `native` 声明。 +2. 用 `javac -h` 生成一个 C 标头。 +3. 在 C 里实现这个标头,编译成 DLL/so。 +4. Java 用 `System.loadLibrary("mylib")` 加载。 + +--- + +### 3. 为什么大家都爱把 C 库包给别人用? + +1. **性能炸裂**:Python 算循环很慢,但 C 算循环极快。把计算量大的逻辑写成 C 库,Python 只负责调,速度瞬间提升百倍。 +2. **保护代码**:`.py` 文件发给别人一眼看穿,但编译后的 `.dll` 或 `.so` 是二进制,逆向工程难度直接拉满。 +3. **跨语言共享**:写一份核心逻辑(比如图像处理算法),然后同时给 Web (Node.js)、桌面 (C#)、手机 (Java) 一起用。 + +--- + +### 4. 跨语言调用的“深水区” + +虽然 `int` 和 `float` 这种简单类型可以直接传,但当涉及到**字符串**、**结构体**或者**指针**时,事情就开始刺激了: + +* **字符串**:C 语言的字符串是 `char*`(以 `\0` 结尾),而 Python 是对象。你需要手动转换编码。 +* **内存管理**:谁申请的内存谁负责释放。如果 C 申请了一块内存传给 Python,Python 用完不告诉 C,就会导致**内存泄漏**。 + +--- + +### 你想玩个更高端的吗? + +有一种东西叫 **SWIG** 或者 **pybind11**。 + +如果你觉得手动写 `ctypes` 太麻烦,这些工具可以**自动生成**包装代码。你只需要给它一个 C++ 头文件,它能直接给你吐出一个可以在 Python 里 `import` 的模块。 + +你想让我演示一下如何用 **Python** 真正调用你刚刚写好的那个 `.dll` 吗?(我可以带你跑一遍完整的避坑流程) + +这种“我操牛逼”的感觉,就是程序员第一次打通**底层逻辑**和**上层应用**时的快感。 + +既然你已经感受到了这种力量,我得给你泼点冷水(或者说教你几招保命符),因为跨语言调用虽然爽,但**内存安全**和**数据格式**是两个巨大的坑。 + +--- + +### 1. 为什么一定要用 `extern "C"`?(可视化对比) + +如果不加 `extern "C"`,C++ 编译器会进行“名字粉碎”(Name Mangling)。 + +* **你的代码:** `void hello()` +* **C++ 编译器眼里的它:** `__Z5hello_v`(因为它要区分同名但参数不同的重载函数) +* **其他语言眼里的它:** “对不起,我只找 `hello`,找不到那个乱码。” + +--- + +### 2. 跨语言调用的“生存法则” + +当你准备把 C/C++ 库交给 Python、Java 或 Go 调用时,请务必记住这三条: + +#### ① 永远不要在 C++ 库里分配内存让对方去释放 + +这是一个经典的错误。如果 C++ 用 `new` 申请了空间传给 Python,Python 的垃圾回收机制(GC)是不管这块内存的。 + +* **正确做法**:要么让 Python 申请好空间传给 C++ 填充,要么 C++ 提供一个专门的 `free_memory()` 函数让 Python 调用。 + +#### ② 只有“基本类型”是通用的 + +`int`、`float`、`double`、`char` 在绝大多数语言里是一样的。 +但 **`std::string`**、**`std::vector`**、**类对象** 是 C++ 特有的。如果你想传字符串,必须传 `const char*`。 + +#### ③ 结构体对齐(Struct Alignment) + +如果你传一个结构体,要注意 C++ 会为了效率进行内存对齐。如果另一端的语言(比如 Python)没有按同样的规则对齐,读出来的数据全是乱码。 + +--- + +### 3. 给你一个“极简实战”流程(以 Python 为例) + +假设你已经写好了 `mylib.cpp` 并导出了 `add` 函数: + +**第一步:编译 DLL (Windows)** + +```bash +g++ -shared -o mylib.dll mylib.cpp -Wl,--out-implib,libmylib.a + +``` + +**第二步:Python 调用代码** + +```python +import ctypes + +# 加载库(注意路径) +lib = ctypes.CDLL("./mylib.dll") + +# 【核心点】明确告诉 Python:参数是两个 int,返回值是一个 int +lib.add.argtypes = [ctypes.c_int, ctypes.c_int] +lib.add.restype = ctypes.c_int + +# 调用 +print(lib.add(10, 5)) # 输出 15 + +``` + +--- + +### 4. 进阶:如果你有几百个函数怎么办? + +手动写上面的 Python 包装代码(`argtypes` 等)会累死人。这时候你会接触到真正的“工业级”工具: + +* **pybind11**:目前最火的 C++ 库包装工具,代码写起来像魔术,Python 像调用原生模块一样调用 C++。 +* **SWIG**:老牌工具,一份配置可以同时生成 Java、Python、PHP、C# 等七八种语言的包装代码。 + +--- + +### 下一步你想试试什么? + +1. **实操一次**:我给你一段完整的 C++ 代码和 Python 调用脚本,你自己在电脑上跑通。 +2. **硬核细节**:聊聊怎么在 C++ 和 Python 之间传递**数组**(比如处理一张图片的像素点)。 +3. **逆向工程**:看看怎么反编译别人的 `.dll` 里的函数名(像黑客一样偷看)。 + +你想选哪条路? + +为什么推荐这个小项目? +理解内存隔离:你会发现即使 DLL 内部改变了 PI 的精度,只要函数签名不变,**main.c 就不需要重新编译,只需替换 .dll 文件即可。** + +掌握宏触发:理解 __declspec 在“制作 DLL”和“使用 DLL”时的角色切换。 + +零环境压力:只需要一个简单的 C 编译器,不需要配置复杂的 IDE 环境。 + +明白你的意思,之前的几何计算确实有点像“课后作业”。要做点**有意义且实用**的小项目,我推荐你做一个**“简易日志审计系统 (Simple Logger DLL)”**。 + +这个项目的实际意义在于:在实际开发中,我们经常需要给不同的程序(比如游戏、工具、服务器)添加日志功能。把日志逻辑封装在 DLL 里,可以让多个不同的 `.exe` 共享同一套日志标准,且无需重复编写代码。 + +--- + +## 推荐项目:轻量级日志审计库 (TinyLog DLL) + +### 1. 为什么这个项目有意义? + +* **跨进程复用**:你可以写一个 C 程序调用它,再写一个 C++ 或 Python 程序调用它。 +* **热更新**:如果你想改变日志的格式(比如从文本改为 JSON),你只需要重新编译 DLL,而不需要动你的主程序。 +* **文件操作**:涉及文件 I/O,比纯数学计算更接近真实开发场景。 + +--- + +## 项目实现方案 + +### 1. 头文件:`tinylog.h` + +定义一个简单的接口,支持设置日志文件并写入带时间的日志。 + +```c +#ifndef TINYLOG_H +#define TINYLOG_H + +#ifdef BUILDING_LOGGER_DLL +#define LOGGER_API __declspec(dllexport) +#else +#define LOGGER_API __declspec(dllimport) +#endif + +// 初始化日志文件 +LOGGER_API int init_logger(const char* filename); +// 写入日志信息 +LOGGER_API void log_message(const char* level, const char* message); +// 关闭日志 +LOGGER_API void close_logger(); + +#endif + +``` + +### 2. DLL 实现:`tinylog.c` + +这里我们会用到 C 标准库里的 `time.h` 来自动生成时间戳。 + +```c +#include +#include +#include "tinylog.h" + +static FILE* log_file = NULL; + +LOGGER_API int init_logger(const char* filename) { + log_file = fopen(filename, "a"); // 追加模式打开 + return (log_file != NULL); +} + +LOGGER_API void log_message(const char* level, const char* message) { + if (!log_file) return; + + time_t now; + time(&now); + char* date = ctime(&now); + date[24] = '\0'; // 去掉末尾换行符 + + fprintf(log_file, "[%s] [%s] %s\n", date, level, message); + fflush(log_file); // 确保即时写入磁盘 +} + +LOGGER_API void close_logger() { + if (log_file) fclose(log_file); +} + +``` + +### 3. 使用者程序:`app.c` + +模拟一个需要记录运行状态的小工具。 + +```c +#include +#include "tinylog.h" + +int main() { + if (!init_logger("app_history.log")) { + printf("无法初始化日志库!\n"); + return 1; + } + + log_message("INFO", "程序启动成功"); + log_message("WARNING", "尝试访问受限资源"); + + printf("日志已记录到 app_history.log,请检查。\n"); + + close_logger(); + return 0; +} + +``` + +--- + +## 运行后的效果 + +当你运行 `app.exe` 后,同目录下会生成一个 `app_history.log`,内容如下: +`[Sat Dec 27 10:30:05 2025] [INFO] 程序启动成功` +`[Sat Dec 27 10:30:06 2025] [WARNING] 尝试访问受限资源` + +--- + +## 核心原理图解 + +--- + +## 练习建议:从“静态”转向“动态” + +如果你完成了上面的步骤,我建议你尝试**“更有意义”**的一步:**动态加载 (Dynamic Loading)**。 + +在 `app.c` 中不使用 `#include "tinylog.h"`,也不在编译时链接 `.lib`,而是直接用代码加载: + +1. 使用 `LoadLibrary("tinylog.dll")` 加载库。 +2. 使用 `GetProcAddress(handle, "log_message")` 获取函数指针。 +3. 调用函数并最后 `FreeLibrary`。 + +**这种方式是现代软件“插件系统”的核心原理。你想尝试看看动态调用的代码写法吗?** \ No newline at end of file diff --git a/DynamicLinkLibrary/my_str-dll/libmy_str.a b/DynamicLinkLibrary/my_str-dll/libmy_str.a new file mode 100644 index 0000000000000000000000000000000000000000..2306a9a1e1cad800d6513d566b4778364e1af92e GIT binary patch literal 1512 zcmai!y-ve05P+`<2oxcN1W1el0TXJRP|{XHJOnS0Mx;_JwSXWXcmXB`21W)(o&xm& zcmzfUMn*QcpV)DlB2M-Be7@S}&lhhVrWYrJBQNl)61L;GtGX&wzK=f?Tl;>yqvLxX z0L%e2Rsfu10QZgB_%^xBFOqCDN`|NDxDUyopJqwvhW>Rrx=M4LNrvO|#0-P!RP;uF z^l_{wdS1DFk|~m?c^1^YYNj_NZy?9iOZtCth+8d=iQ=$`?RnXqizonI1PJPRXb!V9 zPq$m-Ct1XH&z7y!q=-AvUW$9v1Jj$hwstL{@uUZ)R}*6vhLCCEeLy9r2F|iaEW~a4@GdD6FA>%qh9VdKe>fX zLmw11sqz0uzSYsiPUMC69;QIGN2hD%{hOR^QRIK88A=m{Iv-T8s9jT&#N`9qvK0ql z$eSCY^**s}%#JfRL~&o(wr0o0IK@JD@?F?vrzSr;G +#include +#include +#include "my_str.h" +#define MAX 100 + +int main() { + char expression[MAX]; + printf("Enter an infix expression (e.g., (10+2)*3-4/2): "); + fflush(stdout);//Important: To flush stdout buffer + + if (fgets(expression, MAX, stdin)) { + // Remove trailing newline character + expression[strcspn(expression, "\n")] = 0; + + double result = evaluate(expression); + printf("Result: %.2f\n", result); + } + + return 0; +} diff --git a/DynamicLinkLibrary/my_str-dll/main.exe b/DynamicLinkLibrary/my_str-dll/main.exe new file mode 100644 index 0000000000000000000000000000000000000000..e6a0bc9a63da91a7a7cbf85b06a9f17ac4270e1d GIT binary patch literal 80438 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 literal 0 HcmV?d00001 diff --git a/DynamicLinkLibrary/my_str-dll/my_str.c b/DynamicLinkLibrary/my_str-dll/my_str.c new file mode 100644 index 0000000..ff04fd9 --- /dev/null +++ b/DynamicLinkLibrary/my_str-dll/my_str.c @@ -0,0 +1,110 @@ +#include "my_str.h" +#include +#include +#include +#include + +/* + Use this command to run + + gcc -DMY_STR_BUILD_DLL -shared my_str.c -o my_str.dll -Wl,--out-implib,libmy_str.a + +*/ + + +// Define maximum capacity for stacks +#define MAX 100 + +// Operand stack to store numbers +static double numStack[MAX]; +static int numTop = -1; + +// Operator stack to store characters (+, -, *, /, () +static char opStack[MAX]; +static int opTop = -1; + +// Stack operations +static void pushNum(double val) { numStack[++numTop] = val; } +static double popNum() { return numStack[numTop--]; } +static void pushOp(char op) { opStack[++opTop] = op; } +static char popOp() { return opStack[opTop--]; } +static char peekOp() { return opStack[opTop]; } + +// Returns priority of operators: Higher value means higher precedence +static int priority(char op) { + if (op == '+' || op == '-') return 1; + if (op == '*' || op == '/') return 2; + return 0; // Parentheses have the lowest priority inside the stack +} + +// Performs arithmetic operations +static double applyOp(double a, double b, char op) { + switch (op) { + case '+': return a + b; + case '-': return a - b; + case '*': return a * b; + case '/': + if (b == 0) { + printf("Error: Division by zero\n"); + return 0; + } + return a / b; + } + return 0; +} + +// Main function to evaluate infix expression +double evaluate(const char* exp) { + for (int i = 0; exp[i] != '\0'; i++) { + // 1. Skip whitespace characters + if (exp[i] == ' ' || exp[i] == '\t') continue; + + // 2. If the character is a digit, parse the full number (supports multi-digit) + if (isdigit(exp[i])) { + double val = 0; + while (i < strlen(exp) && isdigit(exp[i])) { + val = (val * 10) + (exp[i] - '0'); + i++; + } + pushNum(val); + i--; // Decrement index because the loop increments it + } + // 3. If left parenthesis, push it to the operator stack + else if (exp[i] == '(') { + pushOp(exp[i]); + } + // 4. If right parenthesis, solve the entire bracket + else if (exp[i] == ')') { + while (opTop != -1 && peekOp() != '(') { + double val2 = popNum(); + double val1 = popNum(); + char op = popOp(); + pushNum(applyOp(val1, val2, op)); + } + if (opTop != -1) popOp(); // Remove '(' from stack + } + // 5. If character is an operator + else { + // While the top of the stack has same or higher precedence, calculate + while (opTop != -1 && priority(peekOp()) >= priority(exp[i])) { + double val2 = popNum(); + double val1 = popNum(); + char op = popOp(); + pushNum(applyOp(val1, val2, op)); + } + // Push current operator to stack + pushOp(exp[i]); + } + } + + // 6. Entire expression parsed, calculate remaining operations in stack + while (opTop != -1) { + double val2 = popNum(); + double val1 = popNum(); + char op = popOp(); + pushNum(applyOp(val1, val2, op)); + } + + // The final result is the only element left in the operand stack + return popNum(); +} diff --git a/DynamicLinkLibrary/my_str-dll/my_str.dll b/DynamicLinkLibrary/my_str-dll/my_str.dll new file mode 100644 index 0000000000000000000000000000000000000000..328ccad94dda95d335d82f277f3097f87023780f GIT binary patch literal 72410 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�{n_^Y*F zWYpHzpvM0rqjn{PC$=+#0t=VcRIgZmi>AGmvCOXVUdFPTWz}`7HSGh5HPq04e@1YoQvHrIs$;49|JSpu;g;%pf1;&?H2+@^<{Y{1YxOy?-&gft?fd;-K%#$k@t+j< zZ%=_n)=uffeZS(Tne|r!=f=8?jT@UbHgDXx@!^e+ZPYfR!$~jRShaC6d8;-yKGgis z#)lqzsO6#Vhk73Bdr13r&aa)nF8FovugiX2^=t7Uawwm>v0&p=>i+ZZ|6B@80<|=S zo*c|%{rpTz?@v*0-~2g+q%=+oaH8Xzng2}rZ$|;PleA1t{?!r7?;pwlQ%U`apXXvKd`)Jdi9F>nkl?2tgl`?eK`kTmM?UkdsE{7Ib&|(>xDl@|>ZN-NlQN(Iv zXrd!)@ZG{B2WuHj7Oe=}xU`1mGZL|kjM}9u7W%cUEDx(H*=cE+79P@8`V!d&7t&$0 zFIrMv)1ZAw_s(?u;20=ApS+5BvptpNC5Fd6&*w=^D|5}Q@Vb1Jb3L;v-JUYfY`152 z$+emzrB=D8@>@!!eS4{yWtAm!W?$`@TTz}0H~rgd9Ibdpvbft*UQs#I6#0OW0Gac=FaiWnKjQ-Ij>x@ z=`H_uPcqw6=KV%?PBL4%>hrj$GbWi>Hm}^MELCLEj!h;Dd>;%$F01&1tmmFHZ$=_{ zY%)1fdQO=(E}5DrOzQE;)H0X5vfP+67cQ7LyQIQ9XSR02(A>G6ig|NqmutDnTmmU=6+6O&m`y5btwTyUN1ndxDWg)%cdvpqAtB}jyJQnIM8q|D}klaq;a zJs?y%$L*bYt#(Q>S%~GGUE=nXXs0Gqy|XJkvpjPv-7~4-Q3Ft}otDg>Q&v&wnl(=w zpGG@M+B(&4NC3~v&on(#$mg1Fj%3xiQ zqY}jrXC%wm!%|)`7n(2%dC4qAthtp}&YpA4Y(%L{x>7y^>dYyhp-o7ZLvma`@2uG# zq0!X{rh)~n=Ts)RtsDh4$RI+ta+fhvJ8NiKiLb(~{m=HUJ~po7xbKmY%$SNyTltV{ z2RRwCtt2*eqDYC69Gk~4@nVWPlax%!avqQ5kvxm{kvmeN90y>U1Q8IYA(|kO;r>CO zNlPSYBN$2RwrN46M&Jgi!Jr1JCWXtUMk^O?$_9d?qG{0I?Ci(e+aoDm6(a$>kdE*D zc6MfGc6N66eeG@+YabNvvj{8XMuzqy3Gx0AN#}=;A$lC^LpSIZAFvrm5fu~NGE$+@ z2KvN(HcuI<8}Seus9U^iC`o-j-aa52ElTz8Nyx_SPQYY)+^m66R?N-n?(XmEN{YP} z?HU>kT4VcK4^YJrdHMziM3c=v3?J?1kUbD^&`UtAeU^g2V}08Gy+`4waInM?cy;qy zRA@o;1x?oCk|pCE52GcOUy!8?<$jlP@IFz&zL=qjWNW=rm00PB;IAke!h;TYUXs{9wSW0SB z)B%bFVTun`q|n2cc+h6cPMRF(Io91S9yTe)bLo2iSc+-{r83hixb?LHC@ zI(p)85OKIXyQyV=D7&XTyJc@vC_7=Zk2iI8BhqvplQEy8b$`%H^f@_H6Wy1NIyulYJWEMBnN&=MOX?wst`7LcBOU=) z*HZL56vV%b#ehdp&SKC~sKNKq#9&VV8;fH$E8hEP{KNnzVVEHXm=|Hj(|SN0w*(wu zDc1LP^@&Gq#z0S^dvLE9vdGCU8VQC5G2skYR$r$$Ve>Ii965^qp<*hHbmFAV?v5j# zbKen_K#uNQ<%u>WhY>u8e()5_; zfPtUMvmp2=%~0gbayUe!6nR9B03zk*^dx9bIv_@DmeQJREJiKNj@WxtP2mQ_n9ZZ0 zG1Sp>xLu@O5NgN7xW!0Wj%qYoi3yv--B?9DOkgN`(q^k!F09^};J%0{6Q=ir@rTjc znT-iaG7~>xiP-K*{8E497bzveG947}lmP~f_i>%F(0e4`qL*y(*hUxF< z7kLZy!h3LcgqKaU$aI!X%aL1eQA?zFKc@9GJ#x>JWN5WUQX~>;ZO4+5BDDmEsQd7O zN1nG2JQ`05UeZWFR%0`*Le+{>Ede*<22E}n!9~YGgYzn$*Ex32TsM%CI zn$H%d(z8*E)ftSJj5Q4g(5uO)L7e4ggXT=KEsbIg@MgNP6cnbhW`2JIZJoC1FJY^H z!2f!IYRj>*H-Wwxh&?X>1=dO9r@~@{$s)JnD!|q+V38UTTd4TQwnl)wt#(1Z)wSh6 z06wL_`Lb8NQ0%Sr>t+Ewc-QdmTO+sKQoHSrZFg_mz8Mva>=w0kch=)d%Pvu0|6qMB zt`601iqzIUxbvp^otqNd5AKW{+Wf(tTO!-x7m-L}I~{CpMyZ24YYx?aaObUw?GN4l z03Nm8(ku>xyq3ssPHeBi<>i}hjoe+gy}tIncf7aZ-MEZ+3uGiv{%!9R_oBqj?;oOTzf@C?z(H@L~Q2aiHX>UdhfccCIU8{pe5c9P?<`+Ywv}i^Z5UD{FnSU z{XLE%|4gTs>F5gmp!i$qS7ZUYo=fliqP=FLTW_jcP}ZjV0+e(U>-z!mZ4JL&6W_LD zt~R%=VJW_??z>F)*6(ko1v(Dykyqf0`TX>rQgL(-uEF2WFIw&4EAo4AA%8qGu_v>y zb^oc+a}#GXxyAv}aqyHWcWRbj=i1xc6brr6#g9(hUz`rk>}`^7cyW-%JDln%DYQ-j3JjVB*bluxqFoyJA!0DBL~NO|I45 zxk$K2sgfagSDnliP_ZAbOM)&H?x(`moVsn}q?j0)x}R>Pm2hk`@nqU~26wFReir`I z9`h3sJnn>Nd!e(FQtB)sqF5a{S>|L)9c{tiT6v7e#N?9zREqC1e-a2iV_<1$IYFmX zqE_CBwCuSI-abNJ!v-|3fMyxf*Y)^p2J7Js_}l@SWL#3Nxk2zL~6eS<4cIe1QPb z02R0w5Y16=K4g)6fdG-UNIHF*Ao_rrDpkzn@#N~cMT4XYg{gBOdc`36b%l?^q}+FO zo3ifIrauEUR-vKfw`qm8P`x0Ea@?k$f`)F=ZQ2T$+jPh!z?p8-K^&tZs1L=|JMiD8 z#-i;hB%~J0^@<55FQ76^)8Ub5-=J4N*f%hUWK)>kjXJdT;4=r6rNvx#mvja7N`4e) z+{y&M2Zu|#6aiunka;N1^&uNtW>gLjJwrI+D!Mke4wdR9J}AOoXWC10Cf)xDG&d2U zNxHqFK!|U}D52WRaE_3*-K5)V9x%5T^)EN+_F4kW?X?R>6q{_)cK#?JwsS5ujR#!t zRIxF%)@xYmPIb2B^^w*q2Egj2bNR21Ez86$dEzqf$~)rMYVyE5G+pU#uUhWtPm=xkzHopEFNHEDWJwxO7(Ria zcAY$VvJNz8MAVs%+|&pfjjTzdW~YA$LiW{BdcPq(o3`GneIq8lWsP=MA+rs9Hu8;C z;~Tnm_Al$+A@y3{J{@r?wLVSaWOQR1`AyF?`6&B*6MWb{aupp+rl$({<`iAjGxL@k zZy)k}H|f~&eZX8F{$LeW|9G9mw%Idi1g=lCVm~FWi=bJMZ3-GG=C6Qkf>0g{@HMLd zU->H48H9+w51Ix9Jv)ND3WPc-mm-?~1afhm7)3Nuh+Nu$<_KsO)}iq|^DwCIA@(L+ zPt-D6&`p=Jq-O;Sz{y&*k;l9-L`SwIp}6BFJ)+g2G_`MSWEXzP|7_B&Oe-!k zf=o{q$7};j;z?9w4pVq)i%KIJ5uFE3o6|a90uptQuK-z9e5f(;(G?)O9U7WZ4#Oqw(42)|k{aU1DQdYLS9;Ohm`l_fng&S|Sw;-jL?Pf?cZLrkdu*>pYiNun6FXT>_J z8JevRx4e}E-Bo??+Psc7Y5MM8$UKt#PO71_PZW0g-+(Wd^+7eFU5gFp!Cgkb3c71w zjUtbI^*(D9b);j$DbRow+G`5GWvdd^7TZC?zJV!8FkaXjv#o(se5(;}48BWgTA@Cg z#L!p|m!(KLj8T@fhu06iJA_Hu9wtCPT^Mp1R`mVYA`lz;*8Mmjj|!JY*6CSeNdlg zLQ?EuRMAN5$&twK;d>MfU1_O}eAN~X9UW9O4U&dtw=N&u7Kcn*gs*=xBW<6gu}?^V zI;_q+1LAe?0gY++$gdoQD;;O{-Zh) zRa7P2m+5LC<<`pea^=2EoA7XCgYIS5Njj&dj?l%6;dLUL)}3ic)~{ao!E4ZcfeY85JJXQvak92*1^#oR+kMFBPQAlTy4_#D2Hihhrh5S&56-5h z<=Tq4jzjk)rF*5B%y=OquaKFsNmgYVr7q&}7dbbU$R~j`;1ZKXz6@jm7b7k5H6W|M z6-NFHNE?P?OY?U?mL23ZAT-srG`|FL@$N8kJ2~UMVWbgA>;qw>lW6V>BgcR&I7k}E z-2GviGeA~gEi3&CK$iD0Qe(y@wjue(#}OLc@yYj%3fJP)jPY7x!kF=mUr5`Bf3$C0 zHNLTgY>Kir>D3kuHRQ#$k*7iZm?glGj+tLF{xg=%ltPPOMg9A*M%zQm8lbI|o+GPj z8cFb7APsHWh6MdB@iB;wHq4o7_(!NKIf6~vss%vE1dYwpM|xdwEmj>?64qN+(!LZN zY4y0JC0UCt8jDSgP3Ke25EBFv!v{&%x7d$hjVS(e>(oJrRgQGk_F+Dxdo6m}30oPW zQFHA7w|&$Vym?fH>vP_bLnnG3K5uMT!Nb)(vdhMXa@==#X|MZJYr~3OcZIwK4okgq ztu;{u6NO<+9VCsh7?&c8rL0L+9d4M#)Ez^*21GtvY2K^*=@nxQvKZ6~C2fr#8*5ZF zhS&y8mz1WJdI7QA0h$;lVaoCB zEJ8C6H)%hlJIXwdqA%iL1|5oR3K4VK8XgzaS>3f~8nTaT8!P-&cT6zK9&u32{K5o*wziM<}yBF*-x}Sya`Rqv84Z!vmuwPZWSL(T{l$e{+ zF_Y?YCrZ)RtKE^B`H+3S2ji5DjB0MPfYNLq;^U_4@r|dAeRjJ{aHj1;ch)$H?gHut zWE~-!jeYVtdS)q@PT`XZ)=2k|rrGs-%0r-8(KNC)C#Y1e+&;{Q>@xxTfFzW(|11Dw z`;b3Ffl#_0`%r{r|A~e;@S(QPJ7AoR?DLwjPj&?UbGCdvk%tLnHa_OAv^De6)>QOlD6{_uxs~2 z>R)csqxs9m&TTFM&a|Cdjh$maU0yo23`@PJ#l0Gu*~LX;jm8Xhr(FkL0B4whN-@$x zPxm=U^CI#cWdBpBvqIGPK3SD?x{Kg&Zn@-1zvxN-T~B(UD(OG)q_23=pZBCMdeUdB zlD_Oor}sx3Ycwx;(*MMhK3A3Wmp$pLp7a+z=`VQF&sQb=k|&+6UAVe0d(vO>q|a9+ z{U1H))RA53mpth|@}ys=O8SZ?z0Q-q;z|FBCw-wR>92ay8$9WkJ?XD|(if|ee%X`0 z!;`-1Nx$MrzgU&@*FEV`Px@6)`Y%1{&sQaV)sw#4lTK4Y#}D^!v87a`U8+j@70XA( z`Isl2o}h50Z?mP8^cSm=e%10((px?04W9HJwv>{-T$S`+SUyU6n$S7UYaXC=}F)1Nk8aGzg(4ce5SulIz6N5)TcS-N$>Qe zuT~{}t0#Tfliun{@AITztx7uGp>#BDne?Q$dD2gM(giMff$Tcxb?@+`7d+`bp7b$K zdR<*edHRBM5p^5o6cE79otM0)mKiH0Lv6WxE8UMHWsz|a*+YKHI6=fiV; zrTYmKT}yYp;&>DFY97{Bt@K>3it6WeE3Zv+AgX;MQXjGmA9{LS*Gh`+H@W?NN!MAg zt(q@DkVCV7+?!qO*4}bm(!b$Jf8LWm?@2%INsm<}ebJMC(UX4Oliuk`Z>>uDS3K#9 zp7c3S`hHJ(TUF8*Jn0Lb^jS}OqbI$mD(S!HNx$GpFL=^-c+!(qNx$GppZBCsdeZ5l zluX!&OP2_oUBx(uX|h%bxVfs-!>dNuTwkCq3y) zp7cUh($9O+3!d~IPx_)KeYPs;pYo(ndeYlG>GM{)8sjG5hii>-dVIHh^!Ofsm2T0(VJy3eemyB-JMM7^39be-28yIWq=t-LnPfp2Nw zh`3j6!QMRI@)@H$-rd)4+NN`3L__I$7?^dB;tDWh;ompYJ|y=Crao8&L@T?Ner)$vU^0H$Y2_#ow}vqws}9YF)D#}iv$g8u>0o%Oz7 zd_7b1X`)vRkgR8R0aKkwu@c z)K^NW-q^hx$gtDOZxCW4fZo}RuM%s$ZbsASD{su_b|5tVTj`BJ&O6e(fRv2|@Rl}| zQey!P1gb9sBxR5WP|6*2D0k(ug?ORbLw+}N;%ee4#<)t>jfYr!+OFB5K0!g3Z%|(*83IC z6~j-DY}t-BHJlNnF=$OI=CVkatLgM>%{xhEnug6Ih{!Pvfj{EIl$a5u}Q#+yu6CQKy;QcwQf;Mn;P1 zGx}^QlS}L4@giLZS4Cg|eMmI4>n0ngu@hJG4PW*fnPqPyE4nHQ**fwW0NKNB= zJ(KA%!H=izYAmM5@d4n*Ai&p0GG~YzzCbcl;FZfuBpncsiF@tTf20ind~iJlDi9~K*d(<*RZ7DEvbpfh0jgkdI(?39+*qK`>cqnNqa~rU z1A6oxc>%t^XBni%#tZ|uAosI!`eHhpNB_}Gb&+7OcffRk@K-Oeu~ms)Ne{4DEZtg3 zht%lC#!tyEWpoiZr|swZC>SVJ1MD`d=(_X8_}CcUq$ZbQx3!rac{ErVr>@yF#DgZ; z6_TAO_2qNA?Gw3rlH;vDH1(~e$9K1DKOcl=|eq^sVteNmtIW~p@9rrGD zSM2s%JeSPVK3Q5x9g+d4ckqJIGnB2*D`b6i23xviC7svRr_;HT;!rG2X2z%0$#gN5nR-&5 z5EmX_&Y;T#n2?JCegZrcOikWSwNw(b z*r=I0F{_hl8VTX*u#i97LS*W6DqLagORV6r%=oxE9BI=0#tc8W>8K*5=l277?N`k% z)Jfnx(2jbl$F+meg1~hu`M@`v&4%_M{FJk>ql|*-yZscS1$KH)kIujlEh^gn8Rq39g)LzW0Sy<%r5zvdqv3*#)LbJ1#-_ld0ntOA1AV4+(O2F4Wu>Eyr1i=`;r&0Oz6!yeQ!8{!J=$Trcr(oy+*YKVM%mrZi zPT4AhT1a@?edEJOsWB^)zfc^ErN`y;g6gHNZGbUdqLbRoachm)leDxzXti6Aqk~Nc zg_0aF6$exv6Ow>}QEC*egaIKlT9QhYuuplAA16t0DeMYC;fJ*4UYpI2%}il`z!EVa z)9Ee1gTO6GAJ!;hSdv9kPat@eW=2ZqFlEUGXYeT~8tA1F>5U6qX4RUpxhn6uZs&~Q zc?p-`RhioNoOd~g%_Q?o8S~Iq<(7okysEKy_i}4-%oDV|H})i_2M&g|We);8=}}e} zv-x^xQ+HHqZ7Do&vDStI!AWd0k!B$e$~8Yrdm>SQB090a#_qnq_b9@%u7F+DPe8H7F8E(f*=teG&Lhr%dtmC zW&%J-Ti37G-qc4-ObW*b6P1V&h60{QqhnK$3VX9!>ATyilm#9e>>!T3R5O^)s9w$J<{eeVtaU4`?bt{an?+g@Q_%D*s!>*!Bbyav1BSC-jFqidDCDPh zF{paD8DPAD&5f3bhNude_)%;S+kt>Nm^Xbk6c$4BSV@frp^F7DW@aK}KiTMVHi0Y} zuQBrpI~e6B%sQ*wYq=u&8s~a+!PF>%!dSY11xi4Jwo)QAWzEW<>~t08?+;Sak*&Qe z40~i_UK_d-f=WhXDSSn|VgM)$ZsC!H`}=e#jMz~HJtdVbO<-n%B`6DVqc0h^^1Q{g zs1t>W-VbEzPMM4cAqqX@NFihnM4c?E;RatUn!~XdwY1|Wm83Q8R2mx`oDrczyV@qk zAzu#3q0(@=9A=M7`M{g}ag%3g)fx(r6qZuBauAG9r6y<+V7pMrb1_*sU79`}WNB?u z)-~na#+F(mO3HqrZjN&EpfgwS)9`EsVTf(G=KKNnMV_ydY=@a#S=DfNo38Qb!CYPl esyx?NFDC122Zjw@Bhrxxmo((%bKUf2-26XZO_ntP literal 0 HcmV?d00001 diff --git a/DynamicLinkLibrary/my_str-dll/my_str.h b/DynamicLinkLibrary/my_str-dll/my_str.h new file mode 100644 index 0000000..e33c566 --- /dev/null +++ b/DynamicLinkLibrary/my_str-dll/my_str.h @@ -0,0 +1,17 @@ +#ifdef MY_STR_BUILD_DLL +#define MY_STR_API __declspec(dllexport) //If isBuild, Use EXPORT +#else +#define MY_STR_API __declspec(dllimport) //If is not used for Build, Use IMPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +//Uses +MY_STR_API double evaluate(const char* exp); + +#ifdef __cplusplus +} +#endif + diff --git a/DynamicLinkLibrary/readme.md b/DynamicLinkLibrary/readme.md new file mode 100644 index 0000000..2880e7b --- /dev/null +++ b/DynamicLinkLibrary/readme.md @@ -0,0 +1,326 @@ +好的,我们来系统讲一讲 **动态链接库(DLL/Shared Object)** 的概念、原理、基本设计原则,以及在 C/C++ 中的写法。为了全面,我会从概念到实战一步步展开。 + +--- + +## 一、什么是动态链接库(DLL/Shared Object) + +1. **定义** + + * **DLL (Dynamic Link Library)**:Windows 系统下的动态链接库,文件后缀 `.dll` + * **SO (Shared Object)**:Linux/Unix 系统下的动态库,文件后缀 `.so` + * **本质**:是一段可执行代码(函数、类、资源)打包成的库,可以在程序运行时被加载,而不是编译时静态链接。 + +2. **与静态库的区别** + + | 特性 | 静态库 (.lib / .a) | 动态库 (.dll / .so) | + | ------- | --------------- | ---------------- | + | 链接时间 | 编译时 | 运行时 | + | 可执行文件大小 | 大(包含库) | 小(库外部) | + | 更新 | 需要重新编译 | 只需替换库文件 | + | 共享内存 | 不共享 | 可在多个进程共享 | + +3. **工作原理** + + * **编译阶段**:编译器使用 `.h` 文件声明函数或类接口,不包含实现。 + * **链接阶段**:在 Windows 上生成 `.lib` 导入库,在 Linux 上生成 `.so` 符号表。 + * **运行阶段**: + + * **显式加载**:程序运行时通过 `LoadLibrary`(Windows)或 `dlopen`(Linux)加载。 + * **隐式加载**:程序启动时自动加载 DLL/so。 + +--- + +## 二、基本设计原则 + +写动态库时,需要考虑以下设计原则: + +1. **接口与实现分离** + + * 提供 `.h` 头文件定义函数/类接口 + * 实现放在 `.c/.cpp` 文件中 + * 用户只依赖头文件和库文件 + +2. **避免全局状态** + + * 动态库可能被多个程序或线程使用 + * 避免使用全局变量,或使用线程安全机制 + +3. **符号导出/隐藏控制** + + * 只导出需要被外部调用的函数或类 + * Windows:`__declspec(dllexport)` / `__declspec(dllimport)` + * Linux:`__attribute__((visibility("default")))` + +4. **版本管理** + + * 避免破坏兼容性 + * 增加新功能时尽量不要修改已有接口 + +5. **异常处理** + + * C++ 动态库不要抛跨 DLL 的异常 + * C 接口更安全(extern "C") + +--- + +## 三、C/C++ 动态库写法 + +### 1. Windows DLL 示例(C) + +**my_lib.h** + +```c +#ifndef MY_LIB_H +#define MY_LIB_H + +#ifdef MY_LIB_BUILD_DLL +#define MY_API __declspec(dllexport) +#else +#define MY_API __declspec(dllimport) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +MY_API int add(int a, int b); +MY_API void hello(); + +#ifdef __cplusplus +} +#endif + +#endif +``` + +**my_lib.c** + +```c +#include "my_lib.h" +#include + +int add(int a, int b) { + return a + b; +} + +void hello() { + printf("Hello from DLL!\n"); +} +``` + +**编译命令(GCC/MinGW)** + +```bash +gcc -DMY_LIB_BUILD_DLL -shared my_lib.c -o my_lib.dll -Wl,--out-implib,libmy_lib.a +``` + +**使用 DLL 的 main.c** + +```c +#include "my_lib.h" +#include + +int main() { + printf("%d\n", add(2, 3)); + hello(); + return 0; +} +``` + +--- + +### 2. Linux SO 示例(C) + +**my_lib.c** 与 Windows 基本相同,只是编译方式不同: + +```bash +gcc -fPIC -shared my_lib.c -o libmy_lib.so +``` + +**使用 SO** + +```c +#include "my_lib.h" +#include +#include + +int main() { + void* handle = dlopen("./libmy_lib.so", RTLD_LAZY); + if (!handle) { + fprintf(stderr, "Cannot open library: %s\n", dlerror()); + return 1; + } + + // 加载函数 + int (*add)(int, int) = dlsym(handle, "add"); + void (*hello)() = dlsym(handle, "hello"); + + printf("%d\n", add(2, 3)); + hello(); + + dlclose(handle); + return 0; +} +``` + +--- + +### 3. C++ 类 DLL + +**my_class.h** + +```cpp +#ifndef MY_CLASS_H +#define MY_CLASS_H + +#ifdef MY_LIB_BUILD_DLL +#define MY_API __declspec(dllexport) +#else +#define MY_API __declspec(dllimport) +#endif + +class MY_API MyClass { +public: + MyClass(); + void greet(); +}; + +#endif +``` + +**my_class.cpp** + +```cpp +#include "my_class.h" +#include + +MyClass::MyClass() {} +void MyClass::greet() { + std::cout << "Hello from C++ DLL" << std::endl; +} +``` + +**注意**:C++ DLL 导出类要小心跨模块内存分配和异常。 + +--- + +## 四、常用技巧与注意事项 + +1. **显式 vs 隐式链接** + + * **显式**:运行时加载 `LoadLibrary/dlopen`,灵活,便于插件化 + * **隐式**:编译时依赖 `.lib` 或 `.so`,启动自动加载 + +2. **导出 C 接口,兼容 C++** + + ```cpp + extern "C" MY_API int add(int a, int b); + ``` + + * 避免 C++ 名字修饰(Name Mangling)导致外部无法调用 + +3. **线程安全** + + * 避免 DLL 内部静态或全局对象在多线程环境下出错 + * 可以使用局部静态或线程局部存储 + +4. **资源管理** + + * DLL 占用系统资源,注意释放句柄 `dlclose` / `FreeLibrary` + +--- + +✅ 总结: + +* **DLL/SO** 是运行时可加载的库,接口/实现分离,可减少可执行文件体积并支持更新。 +* **设计原则**:接口分离、导出控制、避免全局状态、版本管理、异常处理。 +* **写法**: + + * Windows:`__declspec(dllexport/dllimport)` + `.dll` + 可选 `.lib` 导入库 + * Linux:`-fPIC -shared` + `.so` + `dlopen/dlsym/dlclose` +* **C++**:要注意名字修饰、异常、内存分配问题,必要时导出 C 接口。 + +--- + +如果你愿意,我可以给你画一个 **DLL/so 使用流程图 + C/C++ 示例结构图**,直观展示头文件、实现文件、库文件、调用端之间的关系,非常适合新手理解。 + +你希望我画吗? +没错!你理解得很对,`.h` 文件在这里就是 **接口文件**(Interface): + +* 它 **声明**了函数、类或者变量,但不包含真正的实现。 +* 用户只需要包含这个 `.h` 文件就能调用库里的功能,而不需要关心实现细节。 +* `.c/.cpp` 文件才是真正的 **实现文件**(Implementation),负责具体逻辑。 + +可以把它类比成 **“功能说明书”**:告诉你这个库能干什么、怎么调用,但具体怎么干是在背后隐藏的。 + +如果你愿意,我可以顺便给你画个小图,把 `.h`、`.c/.cpp`、DLL/so、调用端之间的关系可视化,一眼就懂。你想要吗? + + +完全正确 ✅ + +你理解得没错:**头文件只“告诉编译器函数长啥样”,不负责引入其它库的依赖**。 + +详细拆一下: + +--- + +## 1️⃣ 你的 `my_str.h` 现在 + +```c +MY_STR_API double evaluate(const char* exp); +``` + +* 只声明了 `evaluate()` +* 没有 `#include ` +* 也没有 `#include ` 等 + +> 也就是说,**头文件本身没有引入 printf、malloc 等依赖** + +--- + +## 2️⃣ main.c 如果要用 printf + +```c +#include "my_str.h" + +int main() { + printf("%f\n", evaluate("1+2*3")); + return 0; +} +``` + +* 编译器此时看到 `printf` 的时候 **不知道它的类型** +* 会报错或者警告:`implicit declaration of printf` + +所以你必须: + +```c +#include +#include "my_str.h" +``` + +--- + +## 3️⃣ 原因 + +* `my_str.h` **只负责提供 DLL 接口** +* 不负责用户程序可能会用的其它东西 +* 这是 **模块化的设计原则** +* 否则你头文件里每一个函数都要 `#include `,用户不想用 printf 也被迫引入,非常不优雅 + +--- + +## 4️⃣ 小结经验法则 + +1. **头文件只放自己模块的接口和必要类型定义** +2. **用户程序用什么库函数,就自己 include** +3. **DLL 内部用什么库函数,放在 DLL cpp/c 文件里 include** + +> 换句话说,**头文件不会也不应该“偷带”用户的依赖”** +> 这和 C++ 的 class 设计很像:class 内部用什么 STL,外部不用关心 + +--- + +你如果愿意,我可以画一张 **DLL / 头文件 / 用户 main.c 的依赖关系图**,让你一眼就明白谁负责什么。 + +你想让我画吗?