第七章 可移植性缺陷
《C陷阱与缺陷》学习笔记
posts
导读
C语言编写的程序能够方便地在不同的编程环境中移植。
7.1 应对C语言标准变更
C语言的标准一直在变化,比如ANSI C
标准是现在用的最多的,但是其一直在增加新的特性。有些人如果没有及时升级,那么可能新版本的代码在他的电脑上就不能运行了。
比如函数原型的概念:
1.double
2.square(double x)
3.{
4. return x*x;
5.}
这样写是不能通过编译的,很奇怪的写法。一般我们都是这样写:
1.double square(double x)
2.{
3. return x*x;
4.}
5.main ()
6.{
7. double a = square(10);
8.}
这样在square声明中表面x是double类型,而不是其他的。
7.2 标识符名称的限制
目前的C语言的标识符是对大小写敏感的,但是在以前版本的ANSI C标准所能保证的是,必须能够区别前6个字符不同的外部名称。而且,这个定义中并没有区分大写字母与其对应的小写字母。 所以编译器禁止使用与库函数同名的标志,即使大小写也不行!
7.3 整数的大小
C语言中有三种不同长度的整数:
- short
- int
- long
C语言的定义中对各种不同类型整数的相对长度作了一些规定:
- 3种类型的整数其长度是非递减的。也就是说,
short
型整数容纳的值肯定能被int
型整数容纳; - 一个普通(
int
类型)整数足够大以容纳任何数组下标; - 字符长度由硬件特性决定(比如
long
类型在32
位和64
位的值可能不同,一个占4
字节,一个占8
字节)。
7.4 字符是有符号整数还是无符号整数
当要把char类型转到int类型,是要将字符作为有符号数还是应该无符号处理?正确的来说是应该作无符号处理的。但是c在转换为无符号的时候会先被转换成int
类型,这样可能得到非预期的效果。
正确的方式是使用语句(unsigned char)c
,因为一个unsighed char类型的字符在转换为无符号整数时无需首先转换为int类型,而是直接进行转换。
7.5 移位运算符
对数进行移位的时候,空出的位会背哦符号位所填充。要注意一个规则:
如果被移位的对象长度是n位,那么移位计数必须大于或等于0,而严格小于n。
举例来说,如果一个int型整数是32位,n是一个int型整数,那么n<<31
和n<<0
这样是合法的,而n<<32
和n<<-1
是非法的。
且可以用移位运算符代替除法运算符,但要被移位的必须是非负数。
1.mid = (low + high) >> 1;
2.mid = (low + high ) / 2;
3.
4.a=a*4;
5.b=b/4;
6.//可以改为
7.a=a<<2;
8.b=b>>2;
说明: 除2 = 右移1位 乘2 = 左移1位 除4 = 右移2位 乘4 = 左移2位 除8 = 右移3位 乘8 = 左移3位
7.6 内存位置0
null指针并不指向任何对象。因此,除非是用于赋值或比较运算,出于其他任何目的使用null指针都是非法的。 不同的编译器有不同的效果,有一些对内存位置0只允许读,不允许写。要检查出这类问题的最简单的办法就是,把程序移到不允许读内存位置0的机器上运行。
7.7 除法运算时发生的截断
假定我们让a除以b,商为q,余数为r:
1.q= a/b;
2.r= a%b;
我们希望a、b、q、r之间维持怎样的关系呢?
- 最重要的一点,我们希望q*b+r==a,因为这是定义余数的关系。
- 如果我们改变a的正负号,我们希望这会改变q的符号,这不会改变q的绝对值。
- 当b>0时,我们希望保证r>=0且r<b。例如,如果余数用于哈希表的索引,确保它是一个有效的索引值很重要。
余数与被除数的正负号要相同,否则上述条件都不能满足。所以在取余的时候尽量避免被余数为负,最好是为无符号数。
7.8 随机数的大小
随机数其实是伪随机数,有一定规律。现在实现随机数会加上时间种子,根据时间的变化产生相应的随机数。 如果想要一定范围的随机数,可以将其对范围值取余。比如1到100的随机数:
1.b=rand()%100;
7.9 大小写转换
1.#define toupper(c) ((c) + 'A' - 'a')
2.#define tolower(c) ((c) + 'a' - 'A')
早起的库函数toupper和tolower是这样实现的。但是有不足之处,如果输入的不是字母就会产生其他垃圾信息。
7.10 首先释放,然后重新分配
大多数c语言实现都为使用者提供了3个内存分配函数:malloc
,realloc
和free
。其他的不说,这个realloc有点陌生。
调用realloc函数时,需要把指针向一块已分配内存的区域指针以及这块内存新的大小作为参数传入,就可以调整这块内存区域为新的大小,这个过程可能涉及到内存的拷贝。
1.free(p);
2.p = realloc (p, newsize);
先释放再分配是第七版参考手册中所规定的。
7.11 可移植性问题的一个例子
看不懂(狗头)
查看原文:http://tanwenbo.top/c/%e7%ac%ac%e4%b8%83%e7%ab%a0-%e5%8f%af%e7%a7%bb%e6%a4%8d%e6%80%a7%e7%bc%ba%e9%99%b7.html