EXEC的解释

本文详细介绍了UNIX环境下进程控制原语exec的功能及使用方法。通过fork创建子进程后,通常会用exec来替换进程映像,执行新程序。文章列举了6种exec函数,并解释了它们之间的区别。

UNIX环境高级编程对EXEC的解释

用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程完全由新程序代换,而新程序则从其 main函数开始执行。因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。有六种不同的exec函数可供使用,它们常常被统称为exec函数。这些exec函数都是UNIX进程控制原语。用fork可以创建新进程,用exec可以执行新的程序。exit函数和两个wait函数处理终止和等待终止。这些是我们需要的基本的进程控制原语

说是exec系统调用,实际上在Linux中,并不存在一个exec()的函数形式,exec指的是一组函数,一共有6个,分别是:

#include <unistd.h>

extern char **environ;

int execl(const char *path, const char *arg, ...);

int execlp(const char *file, const char *arg, ...);

int execle(const char *path, const char *arg, ..., char * const envp[]);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

int execve(const char *path, char *const argv[], char *const envp[]);

其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数


`sqlite3_exec` 是 SQLite C API 中一个**高层接口函数**,用于执行一条或多条 SQL 语句,并可选择性地处理查询结果。它封装了底层的编译、执行和结果回调机制,非常适合快速开发和简单操作。 --- ## ✅ 函数原型 ```c int sqlite3_exec( sqlite3 *db, // 数据库连接句柄 const char *sql, // 要执行的 SQL 字符串 int (*callback)(void*, int, char**, char**),// 回调函数(仅 SELECT 时使用) void *arg, // 传递给回调函数的参数 char **errmsg // 错误信息输出(出错时设置) ); ``` ### 返回值: - `SQLITE_OK (0)`:成功 - 其他值:错误码(如 `SQLITE_ERROR`, `SQLITE_MISUSE` 等) > ⚠️ 如果执行失败且 `errmsg` 不为 `NULL`,SQLite 会自动分配内存并写入错误描述字符串,需调用者手动释放(用 `sqlite3_free()`)。 --- ## 🔹 参数详解 | 参数 | 说明 | |------|------| | `db` | 已打开的数据库连接(由 `sqlite3_open` 创建) | | `sql` | 一串或多个以分号`;`分隔的 SQL 语句 | | `callback` | 每当有结果行时被调用的函数(只用于 `SELECT` 查询) | | `arg` | 用户自定义数据,传给 `callback` | | `errmsg` | 出错时保存错误消息的指针地址 | --- ## 🟡 示例代码:插入 + 查询 ```c #include <sqlite3.h> #include <stdio.h> // 回调函数:处理 SELECT 查询的每一行 static int callback(void *data, int argc, char **argv, char **azColName) { fprintf(stderr, "%s: \n", (const char*)data); for (int i = 0; i < argc; i++) { printf(" %s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); } printf("\n"); return 0; // 返回非零值会中断查询 } int main() { sqlite3 *db; char *err_msg = 0; const char *sql; int rc; // 打开数据库(如果不存在则创建) rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } // 创建表 sql = "CREATE TABLE IF NOT EXISTS users (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "name TEXT NOT NULL, " "age INT);"; rc = sqlite3_exec(db, sql, 0, 0, &err_msg); if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); sqlite3_close(db); return 1; } // 插入数据 sql = "INSERT INTO users (name, age) VALUES ('Alice', 30); " "INSERT INTO users (name, age) VALUES ('Bob', 25);"; rc = sqlite3_exec(db, sql, 0, 0, &err_msg); if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); sqlite3_close(db); return 1; } // 查询数据(使用回调) sql = "SELECT * FROM users;"; rc = sqlite3_exec(db, sql, callback, (void*)"Query Results", &err_msg); if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); } // 关闭数据库 sqlite3_close(db); return 0; } ``` ### 输出示例: ``` Query Results: id = 1 name = Alice age = 30 Query Results: id = 2 name = Bob age = 25 ``` --- ## 🔹 回调函数详解 ```c int callback(void *arg, int argc, char **argv, char **azColName) ``` | 参数 | 含义 | |------|------| | `arg` | 就是传给 `sqlite3_exec` 的第四个参数(如 `"Query Results"`) | | `argc` | 当前行的列数 | | `argv` | 字符串数组,每个元素是该列的值(文本形式),NULL 值为 `NULL` 指针 | | `azColName` | 列名数组(如 `"id"`, `"name"`) | 📌 注意:`argv[i]` 可能是 `NULL`,需要判空! --- ## ✅ 使用场景总结 | 场景 | 是否推荐使用 `sqlite3_exec` | |------|----------------------------| | ✅ 执行 DDL(CREATE, DROP) | ✔️ 非常方便 | | ✅ 执行 INSERT/UPDATE/DELETE | ✔️ 简单直接 | | ✅ 执行 SELECT 并处理结果 | ✔️ 适合小数据量 | | ❌ 大量数据查询或高性能需求 | ✖️ 推荐使用 `sqlite3_prepare_v2` + `step` 循环 | | ❌ 绑定参数防注入 | ✖️ 不支持占位符绑定,容易 SQL 注入! | --- ## ❗ 安全警告:SQL 注入风险 ```c // 危险!拼接用户输入 char sql[512]; sprintf(sql, "SELECT * FROM users WHERE name = '%s'", user_input); sqlite3_exec(db, sql, callback, 0, &err_msg); ``` 👉 如果 `user_input = "'; DROP TABLE users; --"`,会导致删表! ✅ 正确做法:使用预编译语句 `sqlite3_prepare_v2` + `bind` ```c sqlite3_stmt *stmt; const char *sql = "SELECT * FROM users WHERE name = ?"; sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); sqlite3_bind_text(stmt, 1, user_input, -1, SQLITE_STATIC); while (sqlite3_step(stmt) == SQLITE_ROW) { // 处理结果 } sqlite3_finalize(stmt); ``` --- ## ✅ `sqlite3_exec` 内部工作流程 ```text [sqlite3_exec] ↓ 解析 SQL 字符串(分号分割) ↓ 对每条语句调用 sqlite3_prepare_v2 ↓ 执行(sqlite3_step)直到完成 ↓ 如果是 SELECT → 调用用户提供的 callback ↓ 收集错误信息(如有) ↓ 返回最终状态码 ``` > 实际上它是对底层 Prepare/Step/Finalize 流程的封装。 --- ## ✅ 常见错误码 | 错误码 | 含义 | |--------|------| | `SQLITE_OK` | 成功 | | `SQLITE_ERROR` | SQL 语法错误 | | `SQLITE_BUSY` | 数据库忙(被锁) | | `SQLITE_MISUSE` | API 使用不当(如并发访问) | | `SQLITE_CORRUPT` | 数据库文件损坏 | | `SQLITE_PERM` | 权限不足 | 可通过 `sqlite3_errstr(rc)` 获取错误文字描述。 --- ## ✅ 何时不用 `sqlite3_exec`? 虽然方便,但在以下情况应避免使用: 1. **需要绑定参数**(防止注入) 2. **频繁执行相同 SQL**(应预编译重用) 3. **大数据集遍历**(回调效率低) 4. **需要精确控制执行过程**(如暂停、恢复) 👉 应改用: ```c sqlite3_prepare_v2() sqlite3_bind_XXX() sqlite3_step() sqlite3_finalize() ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值