AI开发C语言应用按步走,表达式计算器calc的第二十步,魔法数修复、测试分隔符、位运算截断检查、进制溢出检查

calc20 --- 魔法数修复、测试分隔符、位运算截断检查、进制溢出检查

1. 概述

本次迭代从 suggestions.md 中选取了 4 个待改进项进行修复,涵盖代码质量、测试框架和运行时健壮性三个方面。

修复项:

编号 问题 类型
C1 var_name[32] 魔法数 代码质量
G3 测试文件分隔符与表达式分隔符 ; 冲突 测试框架
G4 位运算截断 int 无警告 运行时健壮性
G5 进制数溢出无检查 运行时健壮性

2. 变更清单

文件 操作 说明
main.c 编辑 var_name[32] → var_name[MAX_NAME](2 处)
test.expr 编辑 分隔符 ; → `````(反引号),避免与表达式分隔符 ; 冲突
Makefile 编辑 IFS=';' → IFS='\'`
eval.c 编辑 新增 #include <limits.h> + check_int_trunc() 函数;6 处 (int) 转换前添加截断检查
parse.c 编辑 新增 #include <errno.h> + #include <stdio.h>;3 处 strtoul 后添加 errno == ERANGE 溢出检查

3. C1 --- var_name[32] 魔法数

3.1 改造前

c 复制代码
char var_name[32];

硬编码的 32,与 parse.h 中 Token.name[32] 无显式关联。

3.2 改造后

c 复制代码
char var_name[MAX_NAME];

MAX_NAME 在 parse.h 中定义为 32,两处统一引用,修改一端时同步更新。

4. G3 --- 测试文件分隔符

4.1 问题

test.expr 使用 ; 作为字段分隔符,但 ; 现在也是合法的表达式分隔符(表达式分隔功能),导致 1;2;3 等表达式无法在测试文件中使用。

4.2 方案

将分隔符改为反引号 `````,原因:反引号在 calc 的词法分析器中永远为非法字符(TOKEN_ERROR),不会与任何合法表达式冲突。

文件 改动
test.expr ; → `````
Makefile IFS=';' → IFS='\'`

同时保留了 ; 作为表达式分隔符的功能不变。

5. G4 --- 位运算截断检查

5.1 问题

eval.c 中位运算操作数先转为 int(32 位),超出 INT_MAX(2147483647)的值被静默截断,用户得不到提示。

5.2 方案

新增 check_int_trunc 函数,在 6 处 (int) 转换前调用:

c 复制代码
static int check_int_trunc(long double v)
{
    if (v > INT_MAX || v < INT_MIN) {
        fprintf(stderr, "  warning: value truncated to int\n");
        return 1;
    }
    return 0;
}

调用位置:parse_bitor、parse_bitxor、parse_bitand、parse_shift(SHL/SHR)、parse_unary(BITNOT)。

6. G5 --- 进制数溢出检查

6.1 问题

parse.c 中 strtoul 解析十六进制/二进制/八进制数字时,超出 unsigned long 范围的值被静默截断为 ULONG_MAX,用户得不到提示。

6.2 方案

在每个 strtoul 调用前重置 errno = 0,调用后检查 errno == ERANGE:

c 复制代码
errno = 0;
val = (long double)strtoul(input_pos, &end, 16);
if (errno == ERANGE)
    fprintf(stderr, "  warning: integer overflow\n");

7. 测试验证

bash 复制代码
$ make test
============================================
  calc --- 测试套件
============================================
  122 passed, 0 failed, 122 total
============================================

全部 122 个回归测试通过,功能不变,新增的检查仅在溢出/截断时输出警告,不影响正常计算结果。

相关推荐
chenbingjie_c16 小时前
C++ 进阶核心知识点总结:模板、内存分区、new/delete、内存池
开发语言·c++
Escalating_xu17 小时前
【C 语言】深入理解指针(1·下):指针运算、野指针、assert 与传址实战
java·c语言·开发语言
实心儿儿17 小时前
Qt — Qt 事件
开发语言·qt
周杰偷奶茶18 小时前
【Java】数据类型与变量
java·开发语言
code斗18 小时前
Java数据结构:堆详解
java·开发语言·数据结构
重生之小比特18 小时前
【C++进阶】map和set
java·开发语言·c++
lie..18 小时前
30天从零开始学AI应用开发(Day 12):像产品一样稳:流式输出、报错重试、花钱控制
开发语言·人工智能·php
傻啦嘿哟18 小时前
Python的默认参数把我坑惨了,原来写[]和写None的区别这么大
开发语言·python·机器学习
阿钱真强道19 小时前
20 嵌入式操作系统 | ubus:把自己的程序状态暴露出去
c语言·进程通信·ubus·ubusd·blobmsg
DeepAgent19 小时前
AI Agent 工程实践(49):一次真实优化——从 Agent v1 到 v2
开发语言·人工智能·agent