K&R习题3.4:补码下itoa无法处理最大负整数问题咨询
K&R 习题3.4 解答
故障原因理解正确性确认
你的理解完全正确。
补码体系下有符号整数的取值范围天然不对称:N位补码可表示的范围是[-2^(N-1), 2^(N-1)-1],最大负整数没有对应的正数值,对其执行取负操作属于有符号整数溢出,是C标准规定的未定义行为,绝大多数编译器实现中该操作的结果仍然是原最大负整数。
原函数中if ((sign=n)<0) n=-n;的逻辑在n等于INT_MIN(即最大负整数)时,n取负后仍然为负数,后续n%10、n/=10的运算逻辑不符合预期,最终会生成错误的字符串结果,和你的分析完全一致。
修改方案说明
你提出的「先减1转换再修正个位」的方案是可行的,实现时可以直接引入<limits.h>头文件的INT_MIN宏做判断,不需要手动适配不同位宽的机器,兼容性更强。
除此之外还有更简洁的通用方案:利用无符号整数的取值范围覆盖所有有符号整数的绝对值,全程用无符号整数做运算,避免溢出问题,修改后的代码如下:
#include <limits.h> void itoa(int n, char s[]){ int i, sign; unsigned int num; sign = n; // 负数转对应无符号绝对值,无溢出问题 num = (n < 0) ? (unsigned int)(-n) : (unsigned int)n; i = 0; do { s[i++] = num % 10 + '0'; } while ((num /= 10) > 0); if (sign < 0) s[i++] = '-'; s[i] = '\0'; // 原代码此处为'\n'属于笔误,应为字符串结束符 reverse(s); }
内容的提问来源于stack exchange,提问作者PwNzDust
相关产品推荐
相关产品推荐

