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类型(但返回值要是一个结构体的话也是很少见的)。