当前位置:网站首页>C陷阱与缺陷 第7章 可移植性缺陷 7.11 可移植性问题的一个例子
C陷阱与缺陷 第7章 可移植性缺陷 7.11 可移植性问题的一个例子
2022-08-01 21:00:00 【weixin_客子光阴】
可移植性问题的一个例子
作用是:把给出的long型整数转换为十进制表示,而且对十进制表示中的每个字符都调用
函数指针所指向的函数:
void printnum(long n, void (*p)())
{
if (n < 0) {
(*p) ('-');
n = -n;
}
if (n >= 10) {
printnum(n / 10, p);
}
(*p)((int)(n % 10) + '0');
}
可移植性问题分析如下:
第一个问题出在该程序把n的十进制表示的末尾数字转换为字符形式时所用的方法上。给它加上'0'来得到对应的字符表示却不一定合适。程序的加法操作嫁定了在机器的字符集中数字是顺序排列且没有间隔的。解决办法是使用一张代表数字的字符表。因为一个字符串常量可以用来表示一个字符数组,所以在数组名出现的地方都可以用字符串常量来替换。
下面的表达式是合法的:
"0123456789"[n % 10]
void printnum(long n, void (*p)()) {
if (n < 0) {
(*p)('-');
n = -n;
}
if (n >= 10) {
printnum(n/10, p);
}
(*p)("0123456789"[n % 10]);
}
第2个问题与n<0时的情形有关。上面的程序首先打印一个符号,然后把n设置为-n。这个赋值操作有可能发生溢出,因为基于2的补码的计算机一般允许表示的负数取值范围要大于正数的取值范围。
解决的方法如下:
最明显的一种方法是把-n赋给一个unsigned long型的变量,然后对这个变量进行操作。但是,我们不能对-n求值,因为这样做将引起溢出!
无论是对基于1的补码还是基于2的补码(1's complement and 2's complement)的机器,改变一个正整数的符号都可以确保不会发生溢出。唯一的麻烦来自于改变一个负号的符号时。因此,如果我们能够不保证不将n转换为对应的整数,那么就能避免这一问题。
译注:有符号整数的二进制表示可以分为3个部分,分别为符号位(sign bit),值位(value bit)和补齐位(padding bit)。补齐位只是填满空白位置,没有什么意义。当符号位矢1时表示负数,根据符号位所代表数值的不同,分为one's complement和two's complement。假设值位共有N位,则
(1)one's complement: 二进制表示的下限-(2^N - 1)。
(2)two's complement: 二进制表示的下限-2^N。
我们可以用同样的方式来处理正数和负数,只不过n为负数时需要打印一个负号。要做到这一点,程序在打印负号之后强制n为负数,并且让所有的算术运算都是针对负数进行的。
printnum函数只检查n是否为负,如果是就打印一个负号。
printneg函数以n的绝对值的相反数为参数。这样,printneg函数就满足了n总为负数或零的条件。
void printneg(long n, void (*p)()) {
if (n <= -10) {
printneg(n/10, p);
}
(*p)("0123456789"[-(n % 10)]);
}
void printnum(long n, void (*p)()) {
if (n < 0) {
(*p)('-');
printneg(n, p);
} else {
printneg(-n, p);
}
}
使用n/10和n%10来表示n的首位数字与末尾数字,当然还需要适当改变符号。
要解决这个问题,我们可以创建两个临时变量来分别保存商和余数。在除法运算完成之后,检查余数是否在合理范围内;如果不是,则适当调整两个变量。需要改动的是printneg函数。
void printneg(long n, void (*p)()) {
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]);
}
原因是我们所处的是一个编程环境不断变化的世界,尽管软件看上去不向硬件那么实在,但大多数软件的生命期却要长于它运行其上的硬件。努力提高软件的可移植性,实际上延长了软件的生命期。
边栏推荐
猜你喜欢
随机推荐
徒步,治好了我的精神内耗
Convolutional Neural Network (CNN) mnist Digit Recognition - Tensorflow
30+的女性测试人面试经验分享
Pytorch框架学习记录8——最大池化的使用
密码学的基础:X.690和对应的BER CER DER编码
[Energy Conservation Institute] Application of Intelligent Control Device in High Voltage Switchgear
system collection
Simple test of the use of iptables
Goroutine Leaks - The Forgotten Sender
Which websites are commonly used for patent searches?
win10版本1803无法升级1903系统如何解决
宝塔搭建PESCMS-Ticket开源客服工单系统源码实测
面试突击70:什么是粘包和半包?怎么解决?
Buttons with good user experience should not have hover state on mobile phones
LeetCode每日一题(1807. Evaluate the Bracket Pairs of a String)
To promote energy conservation institute 】 【 the opinions of the agricultural water price reform
idea实用快捷键合集——持续更新
Use WeChat official account to send information to designated WeChat users
如何让定时器在页面最小化的时候不执行?
[译] 容器和 Kubernetes 中的退出码完整指南