首页 百科知识 可移植性问题的一个实例

可移植性问题的一个实例

时间:2023-09-22 百科知识 版权反馈
【摘要】:如果是,则它的十进制表示中包含两个或更多个数字,因此我们递归地调用printnum()来打印除最后一个数字外的所有数字。这个程序——由于它的简单——具有很多可移植性问题。问题仅出在改变一个负数的符号时。我们同时改变了printneg()的函数体来适应n永远是负数或零这一事实。调用整数除法的行为在其中一个操作数为负的时候是实现相关的。

7.9 可移植性问题的一个实例

    让我们来看一个已经被很多人在很多时候解决了的问题。下面的程序带有两个参数:一个长整数和一个函数(的指针)。它将整数转换位十进制数,并用代表其中每一个数字的字符来调用给定的函数。

 

void printnum(long n, void (*p)()) {

    if(n < 0) {

        (*p)('-');

        n = -n;

    }

    if(n >= 10)

        printnum(n/ 10, p);

    (*p)(n % 10 +'0');

}

 

    这个程序非常简单。首先检查n是否为负数;如果是,则打印一个符号并将n变为正数。接下来,测试是否n >= 10。如果是,则它的十进制表示中包含两个或更多个数字,因此我们递归地调用printnum()来打印除最后一个数字外的所有数字。最后,我们打印最后一个数字。

 

    这个程序——由于它的简单——具有很多可移植性问题。首先是将n的低位数字转换成字符形式的方法。用n % 10来获取低位数字的值是好的,但为它加上'0'来获得相应的字符表示就不好了。这个加法假设机器中顺序的数字所对应的字符数顺序的,没有间隔,因此'0' + 5'5'的值是相同的,等等。尽管这个假设对于ASCIIEBCDIC字符集是成立的,但对于其他一些机器可能不成立。避免这个问题的方法是使用一个表:

 

void printnum(long n, void (*p)()) {

    if(n < 0) {

        (*p)('-');

        n = -n;

    }

    if(n >= 10)

        printnum(n/ 10, p);

   (*p)("0123456789"[n % 10]);

}

 

    另一个问题发生在当n< 0时。这时程序会打印一个负号并将n设置为-n。这个赋值会发生溢出,因为在使用2的补码的机器上通常能够表示的负数比正数要多。例如,一个(长)整数有k位和一个附加位表示符号,则-2k可以表示而2k却不能。

 

    解决这一问题有很多方法。最直观的一种是将n赋给一个unsigned long值。然而,一些C便一起可能没有实现unsigned long,因此我们来看看没有它怎么办。

 

    在第一个实现和第二个实现的机器上,改变一个正整数的符号保证不会发生溢出。问题仅出在改变一个负数的符号时。因此,我们可以通过避免将n变为正数来避免这个问题。

 

    当然,一旦我们打印了负数的符号,我们就能够将负数和正数视为是一样的。下面的方法就强制在打印符号之后n为负数,并且用负数值完成我们所有的算法。如果我们这么做,我们就必须保证程序中打印符号的部分只执行一次;一个简单的方法是将这个程序划分为两个函数:

 

void printnum(long n, void (*p)()) {

    if(n < 0) {

        (*p)('-');

        printneg(n,p);

    }

    else

       printneg(-n, p);

}

 

void printneg(long n, void (*p)()) {

    if(n <= -10)

        printneg(n/ 10, p);

   (*p)("0123456789"[-(n % 10)]);

}

 

    printnum()现在只检查要打印的数是否为负数;如果是的话则打印一个符号。否则,它以n的负绝对值来调用printneg()。我们同时改变了printneg()的函数体来适应n永远是负数或零这一事实。

 

    我们得到什么?我们使用n /10n % 10来获取n的前导数字和结尾数字(经过适当的符号变换)。调用整数除法的行为在其中一个操作数为负的时候是实现相关的。因此,n % 10有可能是正的!这时,-(n % 10)是负数,将会超出我们的数字字符数组的末尾。

 

    为了解决这一问题,我们建立两个临时变量来存放商和余数。作完除法后,我们检查余数是否在正确的范围内,如果不是的话则调整这两个变量。printnum()没有改变,因此我们只列出printneg()

 

void printneg(long n, void (*p)()) {

    long q;

    int r;

    if(r > 0) {

        r -= 10;

        q++;

    }

    if(n <= -10){

        printneg(q,p);

    }

   (*p)("0123456789"[-r]);

}

 

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈