跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
C 语言防御性编程
”︁
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
{{DISPLAYTITLE:C语言防御性编程}} '''防御性编程'''(Defensive Programming)是一种软件开发实践,旨在通过预见和处理潜在的错误条件,提高程序的健壮性和可靠性。在C语言中,由于缺乏现代语言(如异常处理机制或自动内存管理)的安全特性,防御性编程尤为重要。本章将详细介绍C语言中的防御性编程技术,包括输入验证、错误处理、断言使用和资源管理等。 == 概述 == 防御性编程的核心思想是:**假设任何可能出错的地方都会出错**,并提前采取措施防止或处理这些错误。在C语言中,常见的防御性编程技术包括: * 检查输入参数的有效性 * 验证指针是否为空 * 处理边界条件(如数组越界) * 使用断言(assert)捕获逻辑错误 * 确保资源(如内存、文件句柄)的正确释放 == 输入验证 == 在C语言中,未经验证的输入是许多错误的根源。以下是一个简单的例子,展示如何验证用户输入: <syntaxhighlight lang="c"> #include <stdio.h> #include <limits.h> void safe_input() { int num; printf("请输入一个正整数(1-100):"); if (scanf("%d", &num) != 1 || num < 1 || num > 100) { printf("输入无效!\n"); // 清除输入缓冲区 while (getchar() != '\n'); } else { printf("输入有效:%d\n", num); } } int main() { safe_input(); return 0; } </syntaxhighlight> '''输出示例:''' <pre> 请输入一个正整数(1-100):-5 输入无效! </pre> === 解释 === * `scanf`的返回值用于检查输入是否成功(返回1表示成功读取一个整数)。 * 检查输入范围(`num < 1 || num > 100`)确保数值在有效范围内。 * `while (getchar() != '\n');`用于清除输入缓冲区中的无效字符,防止后续输入错误。 == 指针验证 == C语言中未初始化的指针或空指针可能导致程序崩溃。防御性编程要求在使用指针前检查其有效性: <syntaxhighlight lang="c"> #include <stdio.h> #include <stdlib.h> void process_data(int *data, size_t size) { if (data == NULL || size == 0) { fprintf(stderr, "错误:无效的指针或大小\n"); return; } // 安全处理数据 for (size_t i = 0; i < size; i++) { printf("%d ", data[i]); } printf("\n"); } int main() { int *arr = malloc(5 * sizeof(int)); if (arr == NULL) { perror("内存分配失败"); return 1; } process_data(arr, 5); free(arr); return 0; } </syntaxhighlight> '''关键点:''' * 检查指针是否为`NULL`(`data == NULL`)。 * 检查数组大小是否为0(`size == 0`)。 * 使用`perror`输出错误信息(如内存分配失败)。 == 断言(Assert) == 断言是一种调试工具,用于捕获程序中的逻辑错误。在发布版本中通常会被禁用(通过`NDEBUG`宏定义)。 <syntaxhighlight lang="c"> #include <assert.h> #include <stdio.h> int divide(int a, int b) { assert(b != 0); // 断言:除数不能为0 return a / b; } int main() { printf("%d\n", divide(10, 2)); // 正常输出 printf("%d\n", divide(10, 0)); // 触发断言失败 return 0; } </syntaxhighlight> '''输出示例:''' <pre> 5 Assertion failed: b != 0, file example.c, line 5 </pre> === 注意事项 === * 断言仅用于调试,不应替代运行时错误处理。 * 在发布版本中禁用断言(编译时添加`-DNDEBUG`)。 == 资源管理 == C语言中必须手动管理资源(如内存、文件句柄)。防御性编程要求确保资源被正确释放,即使发生错误。 <syntaxhighlight lang="c"> #include <stdio.h> #include <stdlib.h> void safe_file_operation(const char *filename) { FILE *file = fopen(filename, "r"); if (file == NULL) { perror("文件打开失败"); return; } // 使用goto简化错误处理 if (fseek(file, 0, SEEK_END) != 0) { perror("文件定位失败"); goto cleanup; } long size = ftell(file); if (size == -1) { perror("获取文件大小失败"); goto cleanup; } printf("文件大小:%ld字节\n", size); cleanup: if (file != NULL) { fclose(file); } } int main() { safe_file_operation("example.txt"); return 0; } </syntaxhighlight> '''关键点:''' * 使用`goto`集中处理错误和资源释放(避免重复代码)。 * 检查文件操作(`fseek`、`ftell`)的返回值。 == 实际案例:安全字符串拷贝 == 以下是一个防御性编程的实际案例,实现安全的字符串拷贝函数: <syntaxhighlight lang="c"> #include <stdio.h> #include <string.h> // 安全字符串拷贝(防止缓冲区溢出) void safe_strcpy(char *dest, const char *src, size_t dest_size) { if (dest == NULL || src == NULL || dest_size == 0) { return; } strncpy(dest, src, dest_size - 1); dest[dest_size - 1] = '\0'; // 确保字符串以NULL结尾 } int main() { char dest[10]; safe_strcpy(dest, "这是一个很长的字符串", sizeof(dest)); printf("拷贝结果:%s\n", dest); return 0; } </syntaxhighlight> '''输出示例:''' <pre> 拷贝结果:这是一个很 </pre> === 分析 === * 检查`dest`和`src`是否为`NULL`。 * 使用`strncpy`限制拷贝长度(避免缓冲区溢出)。 * 手动添加NULL终止符(`dest[dest_size - 1] = '\0'`)。 == 总结 == 防御性编程是C语言开发中的重要实践,能够显著提高程序的稳定性和安全性。关键技巧包括: * 始终验证输入和参数。 * 检查指针和资源是否有效。 * 使用断言捕获逻辑错误(仅限调试)。 * 确保资源释放(如内存、文件句柄)。 通过遵循这些原则,可以编写出更健壮、更可靠的C语言程序。 [[Category:编程语言]] [[Category:C]] [[Category:C 语言错误处理]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)