练习 3-4 在数的对二的补码表示中,我们编写的 itoa 函数不能处理最大的负数,即n 等于-2 字长-1的情况。请解释其原因。修改该函数,使它在任何机器上运行时都能打印出正确的值。
错误在于补码表示中正数取值范围比复数小一。补码的表示即为模运算表示法。举个简单的例子,假如计算机表示的位数为3位,即000~111,如果不要求表示负数,那么000~111换算成十进制即为0~7,即计算机只能表示0~7,这就是unsigned int。然而如果要求表示负数的话,那么这三位中有一位需要作为符号位存在。所以最终表示分别为:000:0,001:1, 010:2,011:3,100:-4,101:-3,110:-2,111:-1同样可以表示8个数,但是由于0的存在,所以正数和负数的数量不相等。再举一个例子加深理解(来自百度百科):
#include <stdio.h>
#include <string.h>
void itoa_2(int n, char s[]);
void reverse(char s[]);
int main()
{
int n = (~0U >> 1) + 1;
char s[10];
itoa_2(n, s);
printf("s:%s\n", s);
return 0;
}
void itoa_2(int n, char s[])
{
int i, sign;
sign = n;
i = 0;
do {
if (sign < 0)
s[i++] = -(n % 10) + '0';
else
s[i++] = n % 10 + '0';
} while ((n /= 10) != 0);
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
return;
}
void reverse(char s[])
{
int c, i, j;
for (i = 0, j = strlen(s) - 1; i < j; i++, j--)
{
c = s[i];
s[i] = s[j];
s[j] = c;
}
return;
}