找回密码
 立即注册
查看: 599|回复: 8

时隔八年,Keil C251 在2026年2月发布了最新的补丁版本 5.60.13

[复制链接]
已绑定手机

2

主题

2

回帖

84

积分

注册会员

积分
84
发表于 2026-8-9 20:21:19 | 显示全部楼层 |阅读模式
https://www.keil.com/update/relnotes/AddOn_C251V560_13.htm

Keil C251 版本 5.60.13,发布于…
发布日期:2026 年 2 月 4 日
  • 这只是 C251 编译器工具链的某个更新版本而已。
  • [C251 编译器]
    • 已更正:C251 V5.60 版本生成的代码比之前版本要庞大。例如:void memSet(void near *dest, unsigned char val, unsigned short len) {  unsigned char near *p = dest;  if (len == 0) return;  do {    *p++ = val;    len--;  } while (len != 0);}000000 7D12           MOV      WR2,WR4          <----- needs to be saved because of the next MOV000002 7C5B           MOV      R5,R11           <----- this is useless, R11 could be used directly --+000004 7D03           MOV      WR0,WR6          <----- also useless, WR6 could be used directly -----+000006 4D11           ORL      WR2,WR2          <----- WR4 could be checked directly here then       |000008 6809           JE       ?C0002                                                                |               ?C0003:                                                                               |00000A 7A0950         MOV      @WR0,R5          <------ here ----------------------------------------+00000D 0B04           INC      WR0,#01H00000F 1B14           DEC      WR2,#01H000011 78F7           JNE      ?C0003               ?C0002:000013 22             RET
    • 已更正:在创建更大规模的代码时,就像之前描述的那样,可能会出现这样一个情况:在将变量赋值给寄存器时,编译器可能会覆盖掉那些被无谓使用的寄存器。例如:static uint16_t rxD;static uint8_t rxC;static uint8_t *prxD;static uint16_t rxDAvail;static uint8_t count = 0;static uint16_t buf1Sz;static uint8_t *buf1;static uint8_t buf2Sz;static uint8_t *buf2;void bug(uint8_t c) {    if (rxD == 0) {        rxC = c;        prxD = NULL;        rxDAvail = 0;        if (rxC == 0x13U) {            count++;            prxD = buf2;            rxDAvail = buf2Sz;    } else {            prxD = buf1;            rxDAvail = buf1Sz;        }    }000000 7C5B           MOV      R5,R11           <----- this is useless, R11 could be used directly --+000002 7E370000    R  MOV      WR6,rxC                                                               |000006 4D33           ORL      WR6,WR6                                                               |000008 784B           JNE      ?C0001                                                                |00000A 7A530000    R  MOV      rxC,R5           <------ here ----------------------------------------+00000E 6D22           XRL      WR4,WR4          <----- because of useless and not tracked assignment this overwrites R5000010 7A270000    R  MOV      prxD,WR4                                                              |000014 7A270000    R  MOV      rxDAvail,WR4                                                          |000018 A5BD1319       CJNE     R5,#013H,?C0002  <------ and here ------------------------------------+00001C 7EB30000    R  MOV      R11,count000020 04             INC      A000021 7AB30000    R  MOV      count,R11000025 7E270000    R  MOV      WR4,buf2000029 7A270000    R  MOV      prxD,WR400002D 7E530000    R  MOV      R5,buf2Sz000031 0A25           MOVZ     WR4,R5000033 800C           SJMP     ?C0008               ?C0002:000035 7E270000    R  MOV      WR4,buf1000039 7A270000    R  MOV      prxD,WR400003D 7E270000    R  MOV      WR4,buf1Sz               ?C0008:000041 7A270000    R  MOV      rxDAvail,WR4
    • 已更正:在某些情况下,WR10 中的 R11 部分会被覆盖。例如:static uint8_t demo(uint8_t arg1, uint8_t arg2) {    uint16_t wResult = 0xFFFF;    wResult = arg1 + 1;    wResult = wResult >> arg2;     return wResult & 0xFF;};---- Variable 'arg2' assigned to Register 'R7' ----;---- Variable 'arg1' assigned to Register 'R11' ----000000 0A5B           MOVZ     WR10,R11         ; A=R11000002 0B54           INC      WR10,#01H;---- Variable 'wResult' assigned to Register 'WR10' ----000004 7CB7           MOV      R11,R7           <----- this overwrites part of WR10000006 7D35           MOV      WR6,WR10000008 6005           JZ       ?C0004.....
    • 已更正:NOCASE 不应影响字符串字面量,因为这样可能会导致变量名称的混淆。
    • 已更正:在类型定义中,reentrant 属性被忽略了,没有产生任何提示。例如:
      C code exampletypedef void (footype) (void) reentrant;footype foo;void foo(void) reentrant;
    • 已更正:二维数组的第二个维度的大小计算有误。例如:
      C code examplevoid bug(void) {    unsigned char array[3][5];    array[0][0] = 0;    printf("sizeof(*array) = %d, should be %d\n",           (int)sizeof(*array), (int)sizeof(array[0]));}The size of a pointer to the array was calculated instead of the size of the second dimension.
    • 已更正:在某些情况下,当使用 goto 语句创建嵌套循环时,某些指令会被优化掉。例如:
      C code exampleint bug(void) {    int i;    int j = 2;    int n = 0;    goto lFirst;lNext:    --j;    if (j == 0)        goto lDone;    ++n;             // <--- this is optimized out !!lFirst:    i = 2;    while (i > 0) {        --i;        if (i == 1) // always true            goto lNext;    }lDone:    return n;}The instruction flow was not correctly built by the compiler. The back edge to lNext was ignored.For that reason '++n' was optimized away.
    • 已更正:由于进行了无符号 char 类型的强制类型转换,整数提升操作被忽略了。实际上,在移位操作之前应该先进行整数提升操作。例如:
      C code exampleint bug(int x) {    return ((unsigned char)x)<<9;}
    • 已修复:在某些情况下,编译器出现了崩溃现象。因此,一些优化措施被取消了,而崩溃问题也得到了解决。现在,这些优化措施又重新被启用了,不过对于某些特殊的 CPU 来说,崩溃现象仍然会发生。
  • [L251 链接器/定位器]
    • 已更正:L251 SEGSIZE 指令改变了段的大小,但并未改变其后面的段的大小。
    • 已更正:链接器显示“L48:忽略递归调用”,但在某些情况下并未进行任何递归操作。


AddOn_C251V560_13.rar

13.22 MB, 下载次数: 88

拓展Keil的C代码中断号.zip

6.78 KB, 下载次数: 48

1 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复

使用道具 举报 送花

已绑定手机

19

主题

3549

回帖

8051

积分

论坛元老

积分
8051
发表于 2026-8-9 20:47:38 | 显示全部楼层
时隔八年,C251在2026年2月发布了最新的补丁版本 5.60.13

1,在已能正常使用的 KEIL C251的基础上;

2,再安装这个补丁文件;
3,民间的 拓展中断号到 32个以上的工具软件,
      也要跟着升级用最新版,重新执行拓展中断号一次;
这个补丁文件只是对优化环节的完善


、C251 编译器(核心 9 大类代码生成缺陷修复)
1. 冗余寄存器拷贝导致代码膨胀、变量被覆盖(最主要修复)
优化器无意义复制 R11、WR6、WR4 等字 / 字节寄存器,生成多余 MOV 指令,造成程序体积变大;
多余寄存器拷贝后,后续赋值会意外覆盖寄存器值,引发逻辑错误(串口缓存、计数变量示例);
移位运算场景下 WR10(含 R11)被错误覆写,移位结果出错。
2. 预处理 / 关键字逻辑错误
NOCASE大小写忽略关键字错误作用于字符串字面量,干扰变量名匹配,现已隔离。
3. reentrant 重入属性识别失效
typedef函数指针声明时标注reentrant会被编译器静默忽略,修复后可正常识别重入函数。
4. 二维数组尺寸计算错误
sizeof(*数组)错误计算为指针宽度,而非数组一行的实际字节数,数组边界、内存分配计算出错。
5. goto 嵌套循环优化错误删除代码
多层 goto 跳转循环中,优化器误判分支流,删除有效自增 / 运算语句,业务逻辑丢失。
6. 强制类型转换抑制整数提升(移位运算出错)
(unsigned char)x << 9场景下,编译器未做标准整数提升,移位结果数值错误。
7. 特定优化路径编译器崩溃
部分组合优化逻辑存在空指针 / 越界,导致编译闪退;已恢复大部分优化,仅保留某款特殊 CPU 的规避逻辑。
8. 枚举常量范围检测(V5.60 基础修复,补丁同步固化)
超大枚举值(如0x12345)不再静默截断,抛出C118枚举值越界警告。
9. 多余无效警告清理
同内存空间 extern + 变量定义场景,不再误报C53重定义警告。
、L251 链接定位器 Linker 2 项逻辑修复
SEGSIZE 段尺寸指令失效:修改段大小后,后方内存段不会自动偏移,导致段地址重叠,现已修正地址重排逻辑;
递归调用警告误触发:无递归代码也会弹出L48: IGNORED RECURSIVE CALL,过滤无递归场景的无效告警。
整体改善价值总结
代码体积优化:消除大量冗余寄存器搬运指令,同等优化等级下固件体积缩小;
运行逻辑正确性:解决寄存器覆写、数组尺寸、移位、循环代码丢失等隐性运行 bug;
编译稳定性:修复编译崩溃问题,优化器可完整启用;
工具提示精准化:过滤无效编译 / 链接警告,增加枚举越界风险提示;
链接内存布局可靠:段尺寸配置、递归告警逻辑修复,避免内存重叠、误导性日志。


AddOn_C251V560_13.rar

13.22 MB, 下载次数: 45

拓展Keil的C代码中断号.zip

6.78 KB, 下载次数: 14

回复

使用道具 举报 送花

已绑定手机

2

主题

2

回帖

84

积分

注册会员

积分
84
 楼主| 发表于 2026-8-10 11:27:24 | 显示全部楼层
中断号扩展到 32个以上,要跟着升级

拓展Keil的C代码中断号.zip

6.78 KB, 下载次数: 13

回复

使用道具 举报 送花

865

主题

1万

回帖

2万

积分

管理员

积分
25104
发表于 2026-8-11 20:43:57 | 显示全部楼层
回复

使用道具 举报 送花

已绑定手机

82

主题

218

回帖

698

积分

高级会员

积分
698
发表于 2026-8-12 08:31:11 | 显示全部楼层
同求
回复

使用道具 举报 送花

已绑定手机

8

主题

30

回帖

1224

积分

金牌会员

积分
1224
发表于 2026-8-14 11:51:18 | 显示全部楼层
不容易啊,还以为keil就此放弃了。
回复

使用道具 举报 送花

31

主题

195

回帖

479

积分

中级会员

积分
479
发表于 2026-8-18 14:14:53 | 显示全部楼层
0xfd的BUG修改了没?

点评

更新说明未提及修复0xfd问题  详情 回复 发表于 2026-8-18 14:28
回复

使用道具 举报 送花

16

主题

935

回帖

4165

积分

超级版主

积分
4165
发表于 2026-8-18 14:28:33 | 显示全部楼层
xhbw*** 发表于 2026-8-18 14:14
0xfd的BUG修改了没?

更新说明未提及修复0xfd问题
回复

使用道具 举报 送花

8

主题

89

回帖

996

积分

高级会员

积分
996
发表于 3 天前 | 显示全部楼层
最近总是遇到莫名其妙的问题,更新一下试一试看
希望这个世界让我装一次B
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-9-22 10:32 , Processed in 0.074681 second(s), 94 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表