57、读C陷阱和缺陷(C Traps and Pitfalls)(三)
5、预处理器
使用预处理器大致有两个方向的原因:
(1)需要将某个变量在程序中所有实现的实例全部修改。
这一条在C++中已用const定义变量替代了。
(2)宏处理,来替代一个简单的函数,如putchar等。
这一条在C++中已用内联函数替代了。
宏只对文本起作用,提供了一种对组成C程序的字符进行变换的方式,面并不作用于程序中的对象。不能忽视宏定义的中空格;最好在宏定义中把每个参数都用括号括起来,同样把整个结果表达式也用括号括起来。
此外宏可能会遇到的尴尬可能是在自增和自减中违背了原来的意思:
#define abs(x) ((x)>=0?(x):-(x))
abs(x);//则可能出问题。
宏不是语句。
_FILE_,_LINE_是内建于处理器的宏,会自动扩展为所在文件的文件名和所处理代码行的行号。
宏不是类型定义。
#define T1 struct Me*
typedef struct Me *T2;
T1 a,b;=>struct Me *a,b;
T2 c,d;=>struct Me *c,*d;
6、Koenig和Moo语录对C++
(1)所谓面向对象编程,就是使用继承和动态绑定机制编程。
(2)用类来表示概念。
(3)避免使用指针。
(4)使用程序库。
(5)避免重复。如果你发现自己在程序的两上不同部分里做了相同的事情,试着把两具部分合并到一个子过程中。如果你发现两个类的行为相近,试着把他们的相似部分统一集中到基类或模块中。
7、可移植性错误
1)如果c是一个字符变量,使用(unsigned)c就可得到与c等价的无符号数,这会失败的。因为在将字符c转换为无符号整数时,c将首先被转换成int型整数,面此时就可能非预期的结果(最高位会扩展,而字符的最高位是1还是0,则关系到扩展后是正数还是负数)。
正确的方法是:使用语句(unsigned char)c,因为一个unsigned char类型在字符在转换成无符号整数时无需要首先转换为int型整数,而是直接进行转换。
2)如果被移位的对象长度是n位,那么移位计数必须大小或等于0,而严格小于n。
3)内存置0
读取和存储指针为NULL的内存,可能发生灾难的后果,如下所示。
int main()
{
char *p=NULL;
cout<<*p;
return 1;
}
4)险法运算时发生的截断
q=a/b;
r=a%b;
在除法和取余关系中,最好维持如下的关系:
A)q*b+r==a
B)如果改变a的正负号,我们希望这会改变q的符号,但这不会影响q的绝对值。
C)当b>0时,希望r>=0,且r<b。余数在哈希表的索引中很有效。
但是可惜的是,上面的三条是矛盾的,只能满足其中的两条。如3/2,q=1时,r=1;先满足第二条,(-3)/2,q=-1,则r=-1,则第三条不满足,如果先满足第三条,r=1,q=-2,则第二条又不满足了。
大多数C编译器放弃了第三条。
例如在取余中,h=n%HASHSIZE,此时h有可能负,如果我们不希望他是负的。可以这样写:
h=n%HASHSIZE;
If(h<0) h+=HASHSIZE;
而更好的做法是避免出现n的值为负这样的情形,并且声明n为无符号数。
5)在移植问题中,一个重要的问题是防止不同机器上对数据的溢出。而这种情况多发生在负数变正数(n=-n)的情况下。因为计算机中用补码来表示数据,而补码中负数比正数大一,这样就有可能在由负数变成正数的情况下发生溢出。
解决这个问题,有好几种方法:
其一:把-n赋给一个unsigned long型的变量,然后对这个变量进行操作,但是我们不能对-n(设n为负数)求值,这样可能引起溢出。
其二:在操作时使n始终是负数。
下面是一个例子,始终用负数进行处理,以防止溢出:
long atol(char *s)
long r=0;
int neg=0;
switch(*s)
{
case '-':
neg=1;
case:'+':
s++;
break;
}
while(*s>='0'&&*s<='9')
{
int n=*s++-'0';
if(neg)
n=-n;
r=r*10+n;
}
return r;
}//
6)表示字符:
'0'+5和'5'的值相同,对ASCII和EBCDIC字符集是正确的,对符合ANSI C的实现也是正确的,但对某些机器对错,正确表示应当是:
“0123456789”[n%10]这样来取字符。因为一个符串常量可以用来表示一个字符数组,所以在数组名出现的地方都可以用字符串常量来替换。
7)测试工作
考查最简单的特例。如数据全为空。
考查边界处理情况。
8)一个异常终止的程序可能没有机会来清空其输出缓冲区,解决方案是:强制不允许对输出进行缓冲,如下所示:
setbuf(stdout,(char*)0);
9)fprintf()函数会把格式字符串当做一个文件结构来处理,所以:
fprintf("error\n")可能会灾难性的后果。正确应当是fprintf(stderr,"error\n")
57、读C陷阱和缺陷(C Traps and Pitfalls)(三)相关推荐
- C陷阱与缺陷(C Traps and Pitfalls)学习笔记
文章目录 3.3 作为参数的数组声明 3.4 避免举隅法 3.5 空指针并非空字符串 3.6 边界计算与不对称边界 3.7 求值顺序 3.8 运算符&&,|| 和 ! 3.9 整数溢出 ...
- C陷阱和缺陷(C Traps and Pitfalls)-读书笔记
C Traps and Pitfalls Chap 01 词法陷阱 1.=是赋值运算符,==表示相等判断. 2.&.|是位运算符号,&&.||是逻辑运算符. 3.词法分析的贪心 ...
- 《C陷阱与缺陷》学习笔记
第一章 词法陷阱 笔记本:<C陷阱与缺陷> 创建时间:2018/4/23 22:06:21 ...
- 【知识点总结】-《C陷阱与缺陷》
目录 第一章:词法的陷阱 1.1."="与"=="不同: 1.3词法分析的"贪心法": 1.4整型常量: 1.5字符与字符串: 第二章:语法 ...
- 《C陷阱与缺陷》一导读
前 言 C陷阱与缺陷 对于经验丰富的行家而言,得心应手的工具在初学时的困难程度往往要超过那些容易上手的工具.刚刚接触飞机驾驶的学员,初航时总是谨小慎微,只敢沿着海岸线来回飞行,等他们稍有经验就会明白这 ...
- c语言局限性,C语言陷阱与缺陷.pdf
C 语言陷阱和缺陷[1] winxos 11-01-28 winxos 11-01-28 原著:Andrew Koenig - AT&T Bell Laboratories Murray Hi ...
- 写给大数据从业者:数据科学的5个陷阱与缺陷
来源 | AI 前线 作者 | 陈炬,责编 | Carol 出品 | CSDN云计算(ID:CSDNcloud) 导读: 这篇分享主要总结了数据从业人员在实践中可能遇到的陷阱与缺陷.跟其他新起的行业一 ...
- 《C语言陷阱和缺陷》笔记
原著:Andrew Koenig - AT&T Bell Laboratories Murray Hill, New Jersey 07094 翻译:lover_P 修订:CQBOY 来自:h ...
- 《C陷阱与缺陷》读后感
<C陷阱与缺陷>读后感 这本书我在亚马逊上买过一本,放在单位了.后来,想再读,于是在淘宝上又买了一本. 这本书很簿,但很有意思 讲了一些C的内幕,感觉很好玩的. 1.为什么C赋值是有=,而 ...
最新文章
- rawquery 没扎到返回什么_Flutter之踩坑的日子(RawQuery的使用)
- 量角器中Selenium定位器的完整指南(示例)
- java golang速度_golang思考之运行速度
- 深入理解卷积层,全连接层的作用意义
- CVPR系列(二)—— 双图层实例分割,大幅提升遮挡处理性能
- C++---容器适配器(stack、queue、priority_queue)
- 【python、pyqt5】,打包出现的若干问题
- 联想服务器修改imm地址,联想服务器IMM运维管理指南.docx
- opencv 二值化处理
- Tomcat 内存溢出对应解决方式
- CentOS7 安装 transmission
- tf1.x版RandLA-Net源码解读
- simulink中不能改名_王者荣耀:万格改名教学,空白名、重复名、个性符号名改法技巧!...
- Python向已有数据的Excel表写入数据
- Asp.Net MVC4.0 官方教程 入门指南之六--查看Edit方法和Edit视图
- QGIS 导入图层到 PostGIS “导入某些图层失败! 图层“public“.‘xxxx‘载入失败 “
- 服务社-企语系统-F_air21.8的Debian11安装方法,也叫协同管理系统
- android来电显示,在Android 9中获取来电显示
- 【Antdv】input type=number去掉上下箭头、提示文字、鼠标滚轮
- mysql 索引 using temporary场景