《C陷阱与缺陷》第六章--预处理器
6.1、不能忽视宏定义中的空格
#define f (x) ((x)-1) //f(x)代表(x)((x)-1)
6.2、宏并不是函数
(1)宏中的每个变量必须加上括号,不然会出现传入表达式时难以预料的结果
(2) 宏中的每个传入的值都会进行多次运算,传入参数会改变某个变量时,会改变多次
(3)使用宏可能会使得语句非常庞大,在进行语句替换的过程中,语句有可能变得异常复杂
6.3、宏并不是语句
滥用宏定义容易导致第3章出现的语义陷阱。
要避免在宏定义中出现语句关键字尽量只使用运算符实现。如果需要用的话一定要仔细推敲。
6.4、宏并不是类型定义
宏定义在定义指针类型时会出现与想象不同的结果,一般的类型定义推荐用typedef
#define TEMP int *
typedef int * temp;
TEMP a1,a2; //相当于 int * a1,a2;只有a1是指针类型,a2不是
temp b1,b2;//相当于 a1,a2都是指针类型
《C陷阱与缺陷》第七章--可移植性缺陷
7.1、应对C语言标准的变更
//使用比较旧的风格定义函数增强可移植性
double fun(x) double x;{
return x;
}
//声明函数的不同
//旧版编译器不支持在在声明函数中包含参数,只能自己显示控制参数类型避免报错。
double fun()
//新版编译器,传int会自动转换成double
double fun(double)
7.2、标示符名称的限制
有些C语言实现不区分大小写或者会自动截断一些长标示符。因此我们在给变量或函数在命名时也应该充分考虑这一点,使我们程序的可移植性更好。
7.3、整数的大小
不同的C语言实现short,int,long所实现的长度都可能不相同。解决的最好办法为设置整数类型为long
7.4、字符是有符号整数还是无符号整数
因为不同的C语言实现对字符的实现是不同的,所以要求字符的整型的时候需要将字符强制转换为无符号整数。(unsigned char)c(不能用(unsigned)c 此转换会先转换成有符号数)
7.5、移位运算符
不同C语言实现在数往右移时无法确定有符号数右边用什么来填充移动的位数。
解决办法为将被移位的对象转为无符号数。这样填充的就都是0
7.6、内存位置0
当一个指针指向null时有些C语言实现允许使用指针对此指针中的内容进行读或写。由于不同的C语言支持不同,因此移植时会出现错误。检查的最好的办法是将程序移植到不允许读和写的C语言实现上运行,找出问题。
7.7、除法运算时发生的截断
在不同C语言上运行除法时。将除数转为无符号数即可避免大部分问题。
7.8、随机数的大小
由于硬件的发展。C语言实现的随机数的范围的实现也出现了分歧。
7.9、大小写的转换
大小写转换中,实现了两套方案。
一种是依据宏定义实现的转换,需要输入都是正确的字母,速度较快
一种是根据函数实现的,不需保证输入的正确性,速度较慢
7.10、首先分配,然后重新释放
一些C语言实现支持内存块释放后还会保存一段时间。
//这样是合法的
free(p);
p=realloc(p,newsize);
有些C语言也不支持这种形式。因此移植时要注意这个问题。