当前位置:网站首页>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]);
}
原因是我们所处的是一个编程环境不断变化的世界,尽管软件看上去不向硬件那么实在,但大多数软件的生命期却要长于它运行其上的硬件。努力提高软件的可移植性,实际上延长了软件的生命期。
边栏推荐
- StringTable Detailed String Pool Performance Tuning String Concatenation
- 线程池处理异常的方法
- 30+的女性测试人面试经验分享
- 漏洞分析丨HEVD-0x6.UninitializedStackVariable[win7x86]
- 【Kaggle】House Prices
- 那些关于DOM的常见Hook封装(一)
- 15 分钟带你入门 Grafana
- 【Dart】dart构造函数学习记录(含dart单例模式写法)
- Which websites are commonly used for patent searches?
- 2022年秋招,软件测试开发最全面试攻略,吃透16个技术栈
猜你喜欢

Interview assault 70: what is the glue bag and a bag?How to solve?

MySQL Syntax Basics

案例:MySQL主从复制与读写分离

JS提升:如何中断Promise的链式调用

MySQL语法基础

有点奇怪!访问目的网址,主机能容器却不行

Zheng Xiangling, Chairman of Tide Pharmaceuticals, won the "2022 Outstanding Influential Entrepreneur Award" Tide Pharmaceuticals won the "Corporate Social Responsibility Model Award"

Hiking, cured my mental internal friction

98.嵌入式控制器EC实战 EC开发板开发完成

Which websites are commonly used for patent searches?
随机推荐
【luogu P1912】诗人小G(二分栈)(决策单调性优化DP)
微服务负载均衡器Ribbon
[Personal work] Wireless network image transmission module
Digital twin Beijing the imperial palace, yuan universe is the process of tourism
Imitation cattle forum project
iptables的使用简单测试
30+的女性测试人面试经验分享
职场如象棋,测试/开发程序员如何突破成长瓶颈期?
Multithreaded producers and consumers
Go Atomic
system collection
LinkedList source code sharing
扣减库存方案
关于Request复用的那点破事儿。研究明白了,给你汇报一下。
织梦模板加入php代码
【Untitled】
Questions I don't know in database kernel interview(1)
"Torch" tensor multiplication: matmul, einsum
外骨骼机器人(七):标准步态数据库
微信小程序云开发|个人博客小程序