SDCC编译时条件判断(x2 + y2 >=800)失效,是否为Bug?
SDCC编译时条件判断失效问题排查
问题现象
这段曼德博集合绘制代码用GCC编译运行完全正常,但用SDCC 4.0.0/4.2.0针对Z80平台编译后,核心条件判断(x2 + y2 >= 800)似乎永远不成立,程序仅输出空格。将变量x和y的类型从int改为long后,程序恢复正常运行,且实际运行中x、y的值从未超过16K范围。
测试代码
#include <stdio.h> void main() { const char* a[8] = {"\x1b[0m", "\x1b[0;41m", "\x1b[0;42m", "\x1b[0;43m", "\x1b[0;44m", "\x1b[0;45m", "\x1b[0;46m", "\x1b[0;47m"}; int x, y; int x2, y2, x0, y0, i, n; char c; int xa = -500; int xb = 300; int ya = 240; int yb = -250; int xd = 7; int yd= 15; int m = 20; y0 = ya; while (y0 > yb) { x0 = xa; while (x0 < xb) { y = 0; x = 0; c = ' '; n = 0; i = 0; while (i < m) { x2 = (x * x) / 200; y2 = (y * y) / 200; if ((x2 + y2) >= 800) { if (i > 9) c = '0'; else c = '0' + i; if (i > 7) n = 7; else n = i; i = m; } y = (x * y / 100 + y0); x = (x2 - y2 + x0); /* if ((x > 16383) || (y > 16383)) printf(" %d %d ", x ,y); */ i++; } printf("%s%c", a[n], c); x0 = x0 + xd; } printf("%s\n", a[0]); y0 = y0 - yd; } }
SDCC编译命令
$ sdcc -mz80 --no-std-crt0 --data-loc 0 sdc-crt0-args.rel sdc-cpm.rel sdc-mandlebrot.c $ sdobjcopy -Iihex -Obinary --gap-fill 0 sdc-mandlebrot.ihx sdc-mandlebrot.com
问题原因
这是16位整数溢出导致的未定义行为,并非SDCC的Bug:
- Z80平台下SDCC的
int是16位有符号整数,取值范围为-32768 ~ 32767 - 代码中计算
x*x时,即使x未超过16K,xx的结果会远大于32767(比如x=16383时,xx≈2.68亿),直接触发16位int的溢出 - GCC在编译时可能默认使用了更大的临时寄存器或优化策略处理溢出,使得计算结果符合预期;但SDCC严格遵循16位int的运算规则,溢出后得到错误的负数或乱码值,导致
x2 + y2永远达不到800的阈值 - 将
x、y改为long后,变量变为32位,足够容纳x*x的计算结果,不会发生溢出,因此逻辑正常执行
结论
代码本身存在跨平台兼容性问题:依赖了GCC对溢出的非标准处理,而SDCC严格遵循16位整数的运算规范,暴露了未定义行为。修改为long类型是正确的修复方式,确保计算过程中不会溢出。
内容的提问来源于stack exchange,提问作者Mike T.
相关产品推荐
相关产品推荐

