读书笔记--C陷阱与缺陷(六)

第六章

1.预处理器:预处理器先对代码进行必要的转换处理,简化编程者的工作。

它的重要原因有以下两点:

a. 假如要将程序中出现的所有实例都加以修改,但希望只改动程序一处数值,重新编译实现。

预处理器可以做到这点,通过将这个数值设为显式常量。

b. C语言函数调用花销大,希望有一个程序块看上去像函数确没有函数调用的开销。

2.宏定义的空格不能忽视

宏定义只是简单的文本替换,记住这个本质可以避免很多错误。

如: #define f  (x)  ((x)-1)

上式意思是: f(x)代表((x)-1)    还是 f 代表(x)((x)-1)

正确答案是后者。因为f与(x)之间多了空格;如果想表达前者的意思,应该定义为如下:

#define f(x)  ((x)-1)

括号也很重要,否则文本替换后运算会产生歧义。

 1 //#define f1  (x)  ((x)-1)
 2 #define f2(x)  ((x)-1)
 3 #define f3(x)  (x)-1
 4 int main()
 5 {
 6
 7     int r1,r2,r3;
 8     //r1=f1(10)*2;
 9     r2=f2(10)*2;
10     r3=f3(10)*2;
11     printf("%d\n %d\n", r2, r3);
12
13     return 0;
14 }

   其实f1的定义是无法通过的,在编译中报错x未定义。

输出:r2=18, r3=8;

因为 r3=(10)-1*2;

所以宏定义的参数最好都用括号括起来!宏调用时的参数不要出现自增自减运算!

3.宏不是类型定义

其实之前章节就说明过使用 typedef 声明类型要由于使用 define;

如:

  

    #define T1 struct foo *
    typedef struct foo *T2;
    T1 a, b;
    T2 c, d;

  a,c,d都可以成功的定义为指向结构的指针,但是b却是定义为结构,非指针。

因为 #define struct foo *a, b; b缺少了*

时间: 2024-10-03 07:07:07

读书笔记--C陷阱与缺陷(六)的相关文章

读书笔记--C陷阱与缺陷(七)

第七章 1.null指针并不指向任何对象,所以只用于赋值和比较运算,其他使用目的都是非法的. 误用null指针的后果是未定义的,根据编译器各异. 有的编译器对内存位置0只读,有的可读写. 书中给出了一种判断编译器如何处理内存0的代码: 1 #include <stdio.h> 2 int main() 3 { 4 5 char *p; 6 p=NULL; 7 printf("location 0 contains: %d\n", *p); 8 9 return 0; 10

读书笔记--C陷阱与缺陷

要参与C语言项目,于是作者只好重拾C语言(之前都是C++,还是C++方便). 看到大家都推荐看看  C陷阱与缺陷(C traps and pitfalls),于是好奇的开始了这本书的读书之旅. 决定将书中重要的知识点和易错点记录下来方便自己复习和他人学习~~不多说了,下面开始. 第一章:词法陷阱 在C语言中,符号(程序文字)之间的空白(包括空格符.制表符.换行符)将被忽略.书中举了一例: 1 if (x > big) big = x; 2 可以写成: 3 if 4 ( 5 x 6 > 7 bi

读书笔记--C陷阱与缺陷(二)

第二章 1. 理解函数声明 书中分析了复杂的类型声明方式,也说明了使用typedef声明会更好理解,推荐大家使用typedef进行函数声明. 书中类型分析一层一层挖掘,让读者可以理解多层嵌套的类型含义,有时间的读者可以去看看,笔者不再重复. 既然书中推荐使用typedef进行函数声明,我们就来研究下typedef: typedef主要用于定义一种类型/结构体的别名. 从字面上看和C的宏定义 #define 挺像的,但是define只是简单的参数替换,如果不注意括号很容易产生预期之外的错误. 在指

读书笔记--C陷阱与缺陷(四)

第四章 1. 连接器 C语言的一个重要思想就是分别编译:若干个源程序可在不同的时候单独进行编译,恰当的时候整合到一起. 连接器一般与C编译器分离,其输入是一组目标模块(编译后的模块)和库文件,输出是一个载入模块(执行文件). 2. 命名冲突与static修饰符 static修饰符可有效减少命名冲突! 如: static int a; 与 int a; 声明含义相同,但是前者限制a的作用域在一个源文件(.c)内,其他源文件是不可见的.但后者都是可见的会产生命名冲突. 如果若干个函数需要共享一组外部

R in action读书笔记(3)-第六章:基本图形

第六章  基本图形 6.1条形图 条形图通过垂直的或水平的条形展示了类别型变量的分布(频数).函数:barplot(height) 6.1.1简单的条形图 6.1.2推砌条形图和分组条形图 如果height是一个矩阵而不是一个向量,则绘图结果将是一幅堆砌条形图或分组条形图.若beside=FALSE(默认值),则矩阵中的每一列都将生成图中的一个条形,各列中的值将给出堆砌的“子条”的高度.若beside=TRUE,则矩阵中的每一列都表示一个分组,各列中的值将并列而不是堆砌. 6.1.3均值条形图

读书笔记(第五、六周)

按接地制式划分,配电系统有TT.IT.TN(TN-S.TN-C.TN-C-S)五种.第一个字母表示电源接地点对地的关系:T -表示直接接地:I -表示不接地或通过阻抗与大地相连:第二个字母表示电气设备的外露导电部分与地的关系:T -表示独立于电源接地点的直接接地:N-表示直接与电源系统接地点或与该点引出导体相连接: 后续字母表示中性线与保护线之间的关系:C -表示中性线N与保护线PE合并为PEN线:S -表示中性线N与保护线PE分开:C-S -表示在电源侧为PEN线,从某点分开为N及PE线. I

读书笔记 - js高级程序设计 - 第六章 面向对象的程序设计

EcmaScript有两种属性 数据属性 和 访问器属性 数据属性有4个特性 Configurable Enumerable Writable Value 前三个值的默认值都为false 举例 Object.defineProperty( person, "name", { writable:false, value:"niko"} ) ; 一旦属性定义为不可配置的,就不能再把它变回可配置的了 读取属性 的特性 var descriptor  = Object.ge

R in action读书笔记(4)-第六章:基本图形(下)

6.3直方图 hist() 其中的x是一个由数据值组成的数值向量.参数freq=FALSE表示根据概率密度而不是频数绘制图形.参数breaks用于控制组的数量.在定义直方图中的单元时,默认将生成等距切分. par(mfrow=c(2,2)) hist(mtcars$mpg)#简单直方图 hist(mtcars$mpg#指定组数和颜色         breaks=12,         col="red",         xlab="Miles Per Gallon&quo

《C陷阱与缺陷》读书笔记

<C陷阱与缺陷>读书笔记 1.编译器中的词法分析器负责将程序分解为一个个符号.C语言中,符号之间的空白 (包括Space ,Tab , Enter) 都将被忽略,但一个符号的中间不能有空白,否则可能被解释成为另一个或几个符号. 2.编译器将程序分解成符号的方法是从左到右逐个字符读入,如果该字符可能会组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分:如果可能,继续读入下一个字符,重复上述判断,直到读入的字符组成的字符串已经不再可能组成一个有意义的