《C专家编程》读书笔记:1~3章

第一章       穿越时空的迷雾

1.       ANSI C中最重要的就是增加了原型。

何谓原型:原型就是函数申明的扩展,这样不仅函数名和返回类型已知,所有的类型参数也是已知的。这就允许编译器在参数的使用和申明之间检查一致性。

2.       赋值

ANSI C标准中规定,要使得赋值形式合法,必须满足下列的条件之一:

两个操作数都是指向有限定符或无限定符的相容类型的指针,左边指针所指向的类型必须具有右边指针所指向类型的全部限定符。

这样,

Char *cp;

Const char *cpp;

//Cpp = cp;    1

// cp = cpp;    2

Cp是一个指向字符的指针,cpp是一个指向const char的指针,所以,

1Cpp 指向cpcpp拥有cp的全部限定符,这样是可以的;

2cp指向cppcp不拥有cpp的限定符const,所以这样赋值的话,编译器会发出警告;

3.       “安静的改变”究竟有多安静?

安静的改变主要聚焦在算数转换,这是非常隐蔽的。

就说一点,unsigned int(sizeof的返回值) int之间进行算数比较的时候,int会被升级为unsinged int。毫无疑问,这是一个地雷。

书中给了一个例子:

int array[] = {23,34,12,17,204,99,16};

#define TOTAL_ELEMENTS  (sizeof(array)/sizeof(array[0])

 main()

{

  int d = -1,x;

if ( d < TOTAL_ELEMENTS - 2)

X = array[d + 1];

}

dTOTAL_ELEMENTS – 2比较的时候,d自动转型为unsigned int,产生一个非常巨大的正整数,致使表达式为假。

要修正这个地雷,只需要改为d < (int)TOTAL_ELEMENTS – 2

 

第二章       这不是bug,而是语言特性;

本章主要分析了C语言的缺陷,分为如下三类:“多做之过”、“少做之过”、“误做之过”。

1. “多做之过”,就是语言中存在某些不应该存在的特性:如switch语句、相邻字符串常量的自动连接、缺省的全局作用域等等。其中,作者提到:“运行时检查与C语言设计理念相违背。按照C语言的理念,程序员应该知道自己正在干什么,并且保证自己的所作所为是正确的”。Switch语句有个fall thought特性,但事实上,97%的情况下,这个特性就会不用,而是程序员在每一个分支后面加上break语句,防止fall though的发生。

2. “误做之过”,就是语言中有误导性质获知不适当的特性,这主要跟C语言的简介有关,很多运算符都重载了。

3. “少做之过”:语言应该提供但是没有提供的特性。

如:允许返回一个指向局部变量的指针,这回产生难以发现的bug。当包含自动变量的函数或者代码退出的时候,它们占用的内存会被回收,它们的内容肯定会被下一个所调用的函数所覆盖,但是原先自动变量的地址有可能被立即覆盖,也有可能稍后覆盖,造成难以发现的bug

 

第三章       C语言的申明

1.”在调用函数的时候,参数从右到左依次压入到堆栈里,作者对这个说法有异议,认为“参数在传递的时候,应该首先尽可能地放到寄存器中”。Int型变量i和一个只包含int的结构体在参数传递的时候可能不同,前者一般传入到寄存器中,而结构参数则很有可能传递到堆栈中。

2.优先级规则:

A.  申明从它的名字开始读取,然后按照优先级顺序依次读取。

B.  优先级从高到低依次是:

1.  申明中被括号括起来的那部分;

2.  后缀操作符:

括号()表示这是一个函数,而方括号[]表示一个数组;

3.  前缀操作符:星号*表示“指向……的指针“

C.      如果const和(或)volatile关键字的后面紧跟类型说明符(如int,long等)那么它作用于类型说明符。在其它情况下,const和(或)volatile关键字作用于它左边紧邻的星号指针

熟读了上面的规则,下面的就是小case了:

const  int  *p1;                p1是一个指针,指向了一个const整数;

int   const  *p2;               同上;

int  *  const  p3;              p3是一个const指针,指向了一个int整数;

const  int * const  p4;           p4是一个const指针,指向了一个const整数;

int  const  *  const  p5;        同上

 

书中还有更变态的例子:

char  *  const  *  (*next)( ); next是一个指针,它指向了一个函数,这个函数没有形参,并且返回了一个指针,这个指针指向了一个指向char类型的const指针。

char  *(* c[10])(int **p): c是一个数组,有10个元素,每一个元素都是一个指针,指针指向了一个函数,这个函数的形参是一个指向指针的指针,该函数返回了一个指向字符的指针。

void (*signal (int sig, void (*func)(int)))(int);

signal是一个函数,这个函数的一个形参是整数,另一个形参是一个函数指针,这个函数指针指向了一个接受整数的形参,没有返回值;signal函数返回了一个指针,指向了一个函数,该函数接受的形参是一个整数,没有返回值。

 

熟悉了书中给出的规则,再复杂的申明都是浮云。

 

你可能感兴趣的:(编程,c,读书,语言,编译器,Signal)