The C Programming Language 2nd(ch4.10 Recursion)的实现为(参数n不能是最小整数):
void printd(int n) {
if (n < 0) {
putchar('-');
n = -n;
}
if (n / 10)
printd(n / 10);
putchar(n % 10 + '0');
}
C Traps and Pitfalls(ch7.11 An example of portability problems)的实现与之类似:
void printnum(long n, void (*p)(int)) {
if (n < 0) {
(*p)('-');
n = -n;
}
if (n >= 10)
printnum(n / 10, p);
(*p)((int)(n % 10) + '0');
}
作者Andrew Koenig从兼容性的角度, 认为最后一条语句有问题. '0'+5得到'5', 是假设计算机是基于ANSI实现的, 字符'0'到'9'才是连续的. 所以应该改为:
(*p)("0123456789"[(n % 10)]);
2个程序正确执行的前提是, 参数n不能是最小整数. 否则n=-n将会导致溢出. 改变正数的符号是不会溢出的, 所以Andrew Koenig把程序改成只处理负数(如果参数是正数, 改变其符号):
void printneg(long n, void (*p)(int)) {
if (n <= -10)
printneg(n / 10, p);
(*p)("0123456789"[-(n % 10)]);
}
void printnum(long n, void (*p)(int)) {
if (n < 0) {
(*p)('-');
printneg(n, p);
} else
printneg(-n, p);
}
这里还有一个假设: n%10(n<0)的值为负数. 但是C语言并没有定义结果的符号, 只能保证表达式r=a%b, 当a>=0且b>0时, 有r>0, |r|<|b|(ch7.7 How does division truncate?). 所以还要修改printneg函数:
void printneg(long n, void (*p)(int)) {
long q;
int r;
q = n / 10;
r = n % 10;
if (r > 0) {
r -= 10;
++q;
}
if (n <= -10)
printneg(q, p);
(*p)("0123456789"[-r]);
}
以下是执行结果(ubuntu 10.4.1 linux, 32bits):
printnum(0x80000000, (void(*)(int))putchar): -2147483648
The C Programming Language 2nd(ch4.10 Recursion)
C Traps and Pitfalls(ch7.11 An example of portability problems)