IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    C陷阱与缺陷之分号

    TacuLee发表于 2015-12-08 16:48:36
    love 0


        在程序中如果不小心多写了一个分号可能不会造成什么不良后果:这个分号也许会被视作一个不会产生任何实际效果的空语句;或者编译器会因为这个多余的分号而产生一条警告信息,根据警告信息的提示提示能够很容易去掉这个分号。一个重要的例外情形是在if或者while语句之后需要紧跟一条语句时,如果此时多了一个分号,那么原来紧跟在if或者while子句之后的语句就是一条单独的语句,与条件判断部分没有了任何关系。考虑下面的例子:

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

        编译器会正常地接受第一行代码中的分号而不会提示任何警告信息,因此编译器对这段程序代码的处理与对下面这段代码的处理就大不相同:

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

        前面的第一个例子(即在if后多加一个分号的例子)实际上相当于

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

        当然,也就等后于(除非x、i或者big是有副作用的宏)

        big = x[i];

        如果不是多写了一个分号,而是遗漏了一个分号,同样会招致麻烦。例如:

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

        此时return语句后面遗漏了一个分号;然而这段程序代码仍然会顺利通过而不会报错,只是将语句

        logrec.date = x[0];

        当作了return语句的操作数。上面这段程序代码实际上相当于:

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

        如果这段代码所在的函数声明返回值为void,编译器会因为实际返回值的类型与声明返回值的类型不一致而报错。然而,如果一个函数不需要返回值(即返回值为void,但使用VS2015测试C++下已经不支持默认返回值,但是C编译器是不检查的),我们经常在函数声明时省略了返回值类型,但是此时对编译器而言会隐含地将函数返回值类型视作int类型。如果是这样,上面的错误就不会被编译器检测到。在上面的例子中,当n>=3时,第一个赋值语句会被直接跳过,由此造成的错误可能是一个潜伏很深、极难发现的程序Bug。

        还有一处情况,也是有分号与没分号的实际效果相差极为不同。那就是当一个声明的结尾紧跟一个函数定义时,如果声明结尾的分号被省略,编译器可以脍 把声明的类型视作返回值类型。考虑下面的例子:

        struct logrec{
               int date;
               int time;
               int code;
        }
        main(){
               …
        }

        在第一个紧随其后的函数main定义之间,遗漏了一个分号。因此,上面代码段实际效果是声明函数main的返回值是结构logrec类型(但返回值要是一个结构体的话也是很少见的)。

        未经允许不得转载:TacuLee » C陷阱与缺陷之分号



      沪ICP备19023445号-2号
      友情链接