C语言缺陷及陷阱读书笔记(二)

语法陷阱##

2.1 理解函数声明###

任何C变量的声明都由两部分组成:类型以及一组类似表达式的声明符(declarator)。

//表示该函数的返回值是一个指向浮点数的指针
float *g();


///表示h是一个指针,h所指向的函数的返回值为浮点类型
float (*h)();

//表示返回值为浮点类型的函数的指针
(float(*)());

((void()())0()表示在计算机启动时,硬件将调用首地址为0位置的子例程。

分析表达式 ((void()())0()

  1. 假设变量fp是一个函数指针,调用该函数指针指向的函数的调用方法为:

    (*fp)()

  2. 找到一个恰当的表达式来替换fp,对(*fp)()进行转换为:指向返回值为void类型的函数的指针:

    void (*fp)()

  3. 调用存储位置为0的子例程

    void (fp)()
    (
    fp) ();

4.对常数0转型为“指向返回值为void的函数的指针”类型,可写成:(void ()()) 0,用(void ()()) 0替代fp,得到(void()())0 ()

5.通过tyepdef可以简化:
typedef void (funcptr) ();
(
(funcptr)0) ();

2.2 运算符的优先级问题###

1.函数调用的优先级要高于单目运算符的:
p为一个函数指针,要调用p所指向的函数:(*p) ()

2.单目运算符是自右向左结合:
p++会被编译成(p++),即取指针p所指向的对象,然后将p递增1

3.任何一个逻辑运算符的优先级低于任何一个关系运算符

4.移位运算符的优先级比算术运算符要低,但是比关系运算符要高

5.任何两个逻辑运算符都具有不同的优先级。所有的按位运算符优先级要比顺序运算符的优先级高,每个“与”运算要比相应的“或”运算符的优先级要高。按位异或运算符的优先级介于按位与运算符和按位或运算符之间。

2.3 注意作为语句结束标识的分号###

if(x[i]>big);
    big=x[i];

if判断语句多写了一个分号,则这个语句单独成为一个语句。相当于语句后多了一个空中括号{}

if(n<3)
    return
logrec.date=x[0];
logrec.time=x[1];
logrec.code=x[2];

第三,四行多了分号,前三行自成一个语句块。导致程序没能达到预期结果。

struct logrec
{
    int date;
    int time;
    int code;

}
int main(void)
{
    .....
}

在第一个}与紧随其后的函数main定义之间,遗漏了一个分号。上面代码实际的效果是声明函数main的返回值是结构logrec类型。

2.4 switch语句###

C语言的switch语句的控制流程能够依次通过并执行各个case部分。
程序员容易遗漏各个case部分的break语句。但有时候刻意隐去break能达到不一样的效果:
加减法程序:

case SUBTRACT:
      opnd2=-opnd2;
case ADD:
      .......

2.5 函数调用###

在函数调用即使函数不带参数,也应该包括参数列表:

f()是一个函数调用语句,而f却不是。

2.6 “悬挂”else引发的问题###

if(x==0)
    if(y==0) error();
else{
        z=x+y;
        f(&z);
}

这段代码当x等于0时,如果y也等于0就进行错误处理,y不等于0的情况下,将x与y之和赋给z,然后以z的地址为参数来调用函数f。但是在程序运行的时候却发生错误,由于C语言中的else始终与同一对括号内最近的未匹配的if结果,所以程序运行时是以下列缩进进行的:

if(x==0){
    if(y==0)
         error();
    else{
        z=x=y;
        f(&z);
}
}

如果x不等于0,程序将不会做任何处理。

改进:

有两种方法可以解决这个问题:

1.将第二个if语句用括号封装起来,这样就不会与else进行结合了。(个人觉得这种方法比较可行)。
2.通过宏定义来解决问题。

posted on 2015-09-20 19:22  陆游君语  阅读(191)  评论(0编辑  收藏  举报

导航