SUNKAIS OS · READ ONLY

Jarvis

登录后,可以询问自己的任务、项目和记录。

登录后使用
Sun KaisPersonal Research Institute · 私人研究机构

Mathematics · Computational Science · Engineering · Personal Knowledge Systems

更多
SUNKAIS · PERSONAL OS

搜索全站功能

选择 前往

LANG-01 · PROGRAMMING WORKBENCH

C

从数据布局、指针和资源生命周期理解程序如何贴近机器运行。

以清晰所有权、编译器警告和动态检查为护栏,建立能编译、能调试、能验证的 C 工程工作流。

MENTAL MODEL / 心智模型

先建立正确的程序直觉

值有类型,内存有边界,资源有唯一生命周期;每个指针都要回答“指向哪里、能用多久、谁来释放”。

CODE REPOSITORY / 代码仓库锚点

从可测试的目录开始

c-project/
├─ CMakeLists.txt
├─ include/app/math_utils.h
├─ src/main.c
├─ src/math_utils.c
└─ tests/test_math_utils.c

QUICK START / 第一条命令

先跑通最小闭环

cc -std=c17 -Wall -Wextra -Wpedantic -Wconversion -g src/main.c -o build/app

LEARNING ROUTE / 学习路径

从写出代码到守住生产边界

每个节点都包含可复制示例、判断原则与常见陷阱。

01常用方法数据、字符串与资源02工程结构头文件与模块边界03构建运行编译、链接与诊断04依赖管理依赖与可复现构建05调试测试断点、调用栈与单元测试06错误诊断常见故障定位07安全边界输入、内存与整数安全
01常用方法

数据、字符串与资源

掌握边界、返回值和资源释放,比记住更多函数更重要。

安全遍历数组代码示例
size_t count = sizeof values / sizeof values[0];
for (size_t i = 0; i < count; ++i) {
    printf("%zu: %d\n", i, values[i]);
}

只适用于当前作用域中的真实数组;数组传给函数后会退化为指针。

检查格式化结果代码示例
int written = snprintf(buffer, sizeof buffer, "%s-%d", name, id);
if (written < 0 || (size_t)written >= sizeof buffer) {
    fputs("output truncated\n", stderr);
}

不要假设目标缓冲区一定足够;始终检查 snprintf 返回值。

单一清理出口代码示例
FILE *file = fopen(path, "rb");
if (file == NULL) return false;
bool ok = read_payload(file);
if (fclose(file) != 0) ok = false;
return ok;

打开资源后,所有路径都必须释放;复杂函数可用 cleanup 标签统一回收。

02工程结构

头文件与模块边界

头文件公开契约,源文件隐藏实现,测试通过公开接口验证行为。

头文件契约代码示例
#ifndef APP_MATH_UTILS_H
#define APP_MATH_UTILS_H

#include <stddef.h>
double mean(const double *values, size_t count);

#endif

公开声明、必要类型和文档;不要在头文件中定义可变全局对象。

最小 CMake 工程代码示例
cmake_minimum_required(VERSION 3.20)
project(memory_lab LANGUAGES C)
add_library(core src/math_utils.c)
target_include_directories(core PUBLIC include)
add_executable(app src/main.c)
target_link_libraries(app PRIVATE core)

用 target 表达依赖、包含路径和编译特性,避免堆积全局选项。

03构建运行

编译、链接与诊断

把警告视为工程反馈,用 Debug 和 Release 两类构建分离排错与性能。

严格编译终端命令
cc -std=c17 -Wall -Wextra -Wpedantic -Wconversion -g src/main.c -o build/app

先解决警告,再讨论优化;不同编译器可追加各自的诊断选项。

CMake 构建终端命令
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build --parallel
ctest --test-dir build --output-on-failure

多配置生成器的 Debug/Release 通常在 --build 阶段用 --config 选择。

运行动态检查终端命令
cc -fsanitize=address,undefined -fno-omit-frame-pointer -g src/main.c -o build/app && ./build/app

AddressSanitizer/UBSan 可暴露越界、释放后使用和多类未定义行为。

04依赖管理

依赖与可复现构建

锁定版本、缩小依赖面,并让构建脚本描述依赖来源。

vcpkg manifest代码示例
{
  "name": "memory-lab",
  "version-string": "0.1.0",
  "dependencies": ["cjson"]
}

把 vcpkg.json 纳入版本控制;使用 baseline 锁定可复现版本。

CMake 发现依赖代码示例
find_package(cJSON CONFIG REQUIRED)
target_link_libraries(app PRIVATE cjson)

链接到导入 target,让 include、库和平台差异跟随依赖声明。

05调试测试

断点、调用栈与单元测试

先保留失败现场,再缩小输入,最后把复现案例固定成测试。

GDB 最短路径终端命令
gdb ./build/app
break main
run
bt
frame 0
print variable

程序应带 -g;崩溃后先看 bt 调用栈,不要急着改代码。

最小断言测试代码示例
#include <assert.h>
#include <math.h>

int main(void) {
    assert(fabs(mean((double[]){2, 4, 6}, 3) - 4.0) < 1e-12);
    return 0;
}

覆盖正常值、空输入、边界长度和错误返回;生产校验不要依赖可被 NDEBUG 关闭的 assert。

06错误诊断

常见故障定位

错误发生位置不一定是根因位置,按编译、链接、运行三个阶段判断。

undefined reference诊断清单
检查:实现文件是否加入 target、声明与定义签名是否一致、库顺序与 C/C++ ABI 是否匹配。

这是链接阶段错误;仅增加 include 不会把实现链接进程序。

segmentation fault诊断清单
保留 core/调用栈 → 用 ASan 重跑 → 检查空指针、越界、释放后使用与栈生命周期。

不要只在崩溃行加空判断;追踪指针从创建到失效的全过程。

结果随机或仅 Release 出错诊断清单
检查未初始化读取、整数溢出、越界、别名与未定义行为;启用 -Wall -Wextra -Wconversion 和 UBSan。

优化常让潜伏的未定义行为以不同方式显现。

07安全边界

输入、内存与整数安全

不信任长度、索引、格式字符串和外部文件;所有转换都要检查范围。

解析整数代码示例
char *end = NULL;
errno = 0;
long value = strtol(text, &end, 10);
if (errno != 0 || end == text || *end != '\0' || value < 0 || value > INT_MAX) {
    return false;
}

atoi 无法可靠区分错误;strtol 需要同时检查 errno、尾指针和业务范围。

分配前防溢出代码示例
if (count > SIZE_MAX / sizeof *items) return NULL;
items = calloc(count, sizeof *items);

先验证乘法不会溢出,再检查分配结果。

安全清单诊断清单
禁止 gets;外部文本不可直接作为 printf 格式串;敏感信息不写日志;依赖和编译器定期更新。

编译器加固是补充,不能替代边界检查和明确所有权。

PRIVATE CODE VAULT / 私人代码仓库

C 私人代码与伪代码仓库

把 C 的练习、工程片段、算法伪代码、验证说明与历史版本保存在登录后的私人空间。

TEXT ONLYRLS PRIVATENO EXECUTION
这里只归档,不运行代码。支持导入与下载纯文本源码;`.mlx`、`.xlsx`、`.accdb` 等二进制容器不会入库。密码、Token、私钥等秘密也会被拒绝,请改用环境变量。
PRIVATE SESSION REQUIRED

登录后打开你的私人仓库

游客只看到这个说明,不会收到、缓存或渲染任何私人源码。

安全登录

REFERENCE SOURCES / 官方与高质量资料

版本差异优先以官方文档为准

先在本站找回路径,再进入原始文档确认版本、平台和完整前置条件。

DELIVERY LOOP / 练习闭环

把每次练习变成可以重新运行的资产

  1. 01 · 定义写清输入、输出、边界与失败行为。
  2. 02 · 最小实现先让单一案例从命令行完整运行。
  3. 03 · 验证增加边界测试、调试信息与质量检查。
  4. 04 · 沉淀提交代码、README、依赖清单和复现命令。