打赏

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

第二章

1. 理解函数声明

书中分析了复杂的类型声明方式,也说明了使用typedef声明会更好理解,推荐大家使用typedef进行函数声明。

书中类型分析一层一层挖掘,让读者可以理解多层嵌套的类型含义,有时间的读者可以去看看,笔者不再重复。

既然书中推荐使用typedef进行函数声明,我们就来研究下typedef:

typedef主要用于定义一种类型/结构体的别名。

从字面上看和C的宏定义 #define 挺像的,但是define只是简单的参数替换,如果不注意括号很容易产生预期之外的错误。

在指针类型声明时最好使用typedef,如下:

typedef char* PCHAR;

#define dpchar char*;

PCHAR p1,p2;

dpchar p3,p4;

上述语句中,p1,p2,p3可以被成功定义为char*,但是p4被定义为char(char* p3,p4;)。

对于结构体,一般定义为:

typedef struct STUDENT_ST

{

      int id;

      char name;

} student;

student st1;//代替struct STUDENT_ST st1,声明更加简单

 

typedef可高效解决平台无关的数据类型,这对公司非常重要,因为不同的项目背景可能使用的系统平台不尽相同,统一的管理数据类型可以避免错误。

如 typedef long double LONGNUM;

或 typedef long LONGNUM;

在跨平台时就可以通过修改typedef来切换数据类型,而不用修改源码,想象下如果修改每个源码里的类型该是多大的工程。。。

 

其实,还可以结合typedef使用bit field方式自定义字节长度的类型,下次有机会详细说明吧~~

 

typedef另一个使用较多的就是书中提到的声明复合类型:

如书中:(* (void (*) ()) 0) ();

可以改写为:typedef void (*pfun) ();

                  (* (pfun) 0) ();

 

2. 运算符优先级

其实记不清运算符优先级的时候怎么办,加括号呗,最多就是括号多了理解起来费时点~

来看看书中推荐的优先级记法:

第一优先级: ()  []  ->  .

其实是括号和调用操作符,很好理解,书中认为不用记,确实如此!

第二优先级: !  ~  ++  --  - (type)  *  &  sizeof

由于第一优先级好理解,单目运算符可认为是最高优先级。

但要注意两点:

  1. 对于 *p() ,因为第一优先级更高所以被解释为 *(p()),要正确调用指针p指向的函数应为 (*p)() 。
  2. 单目运算符是自右向左结合的(与人看文字方向相反)。所以如 *p++ 会被解释为*(p++),加1的是p值;写为 (*p)++,加1的是p指向对象的值;虽然都是取出p指向对象的值。。。。

第三优先级:  *  /  %  -  +  (算术运算符)

第四优先级: <<  >>  (移位运算符)

第五优先级: <  <=  >  >=  ==  !=  (关系/比较运算符)

第六优先级: &  |  ^  (逻辑/位运算符)

第七优先级: &&  ||  (逻辑运算符)

第八优先级: ? :  (条件运算符)

注意:关系/比较运算符中,==  != 的优先级低于其他关系运算符。如书中例子: a < b == c < d  即  (a<b) == (c<d)

逻辑运算符优先级也不相同,一般是”与”>”或”,即 &>^>|>&&>||

所有的赋值运算符(=)优先级一样,但是自右向左结合!!

 

3. 注意分号

主要注意if  while  struct声明。其实这些都比较简单,但是笔者确实遇到过这种问题,当时笔者在if();后加了分号,程序结果一直不对但是检查了很久才发现。。。

struct声明后紧跟函数声明时缺少分号很危险,书中提到编译器会把声明类型视为函数的返回值类型。如:

1 struct rec
2 {
3     int date;
4     int time;
5 }
6 main()
7 {
8     ...
9 }

struct rec的声明结尾没有分号,可能变为main函数的返回类型。。。

 笔者对该程序进行了build,出现了两个warning和1个error:

第一个warning说:main函数的返回类型不是int;

第二个warning说:控制到达非void函数的结尾。通俗说就是应该带有返回值的函数结尾可能无返回值。

error说:类型不匹配,当要返回int却要求返回struct rec

看来优秀的IDE(codeblocks)还是可以避免这类错误的!

 

4. switch语句

书中强调C语言的switch语句能依次通过并执行各个case部分,所以若只想执行一个case要加break;

如:switch (color)

{

      case 1 : printf(“red”);

      case 2 : printf(“yellow”);

case 1 : printf(“blue”);

}

假设color取值2,最后程序打印  yellowblue

因为case2,case3都执行了,所以要加break;

当然如果你想通过刻意去掉break;来实现某些功能,可以这么写,但是代码阅读起来容易产生疑问。

posted @ 2017-08-30 22:20  巴尔扎克_S  阅读(324)  评论(0编辑  收藏  举报