当前位置:网站首页>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]);
}
原因是我们所处的是一个编程环境不断变化的世界,尽管软件看上去不向硬件那么实在,但大多数软件的生命期却要长于它运行其上的硬件。努力提高软件的可移植性,实际上延长了软件的生命期。
边栏推荐
- STAHL touch screen repair all-in-one display screen ET-316-TX-TFT common faults
- Interview Blitz 70: What are sticky packs and half packs?How to deal with it?
- 那些关于DOM的常见Hook封装(一)
- C专家编程 第1章 C:穿越时空的迷雾 1.1 C语言的史前阶段
- AQS原理和介绍
- StringTable Detailed String Pool Performance Tuning String Concatenation
- 98.嵌入式控制器EC实战 EC开发板开发完成
- 响应式织梦模板清洁服务类网站
- 】 【 nn. The Parameter () to generate and why do you want to initialize
- wps excel 插入公式 整列
猜你喜欢
OSG Notes: Set DO_NOT_COMPUTE_NEAR_FAR to manually calculate far and near planes
R语言 线性回归的有关方法
wps excel 插入公式 整列
Hiking, cured my mental internal friction
To promote energy conservation institute 】 【 the opinions of the agricultural water price reform
98. Embedded controller EC actual combat EC development board development completed
30+的女性测试人面试经验分享
写给刚进互联网圈子的人,不管你是开发,测试,产品,运维都适用
网络安全与基础设施安全局(CISA):两国将在网络安全方面扩大合作
"Torch" tensor multiplication: matmul, einsum
随机推荐
Little data on how to learn?Jida latest small learning data review, 26 PDF page covers the 269 - page document small data learning theory, method and application are expounded
Go Atomic
tiup mirror genkey
vant实现Select效果--单选和多选
相亲模型与有限状态机
Qt设置应用程序开机自启 解决设置失败原因
微信小程序云开发|个人博客小程序
外骨骼机器人(七):标准步态数据库
To promote energy conservation institute 】 【 the opinions of the agricultural water price reform
Pytorch框架学习记录12——完整的模型训练套路
仿牛客论坛项目
Telnet弱口令渗透测试
职场如象棋,测试/开发程序员如何突破成长瓶颈期?
【Dart】dart构造函数学习记录(含dart单例模式写法)
【Untitled】
Failed to re-init queues : Illegal queue capacity setting (abs-capacity=0.6) > (abs-maximum-capacity
iptables的使用简单测试
Protocol Buffer usage
MySQL语法基础
扣减库存方案