1、假如使用了禁止while的条件部分进行赋值的变异程序选择项,为什么可以查出下面代码中的un算优先级错误?
while(ch = getchar() != EOF)
答:
编译程序会查获优先顺序错。因为它把表达式解释为:
while( ch = ( getchar() != EOF ) )
换句话说,编译程序把它看作是将表达式的值赋给ch,因而认为你把“==”错误的键为“=”,并向你发出可能有复制错误的警告。
2、看看你怎样使用编译程序查出无意使用的空语句和赋值语句。值得推荐的办法是进行相应的选择,使编译程序能够对下列常见问题产生警告信息。怎样才能消除这些警告信息呢?
a) if(flight == 063)。这里程序员的本意是对63号航班进行测试,但是因为前面多了一个0使063成了八进制数。结果变成对51号航班进行测试。
答:
b)if(pb != NULL & pb != 0xff)。这里不小心把&&写成&,结果即使pb等于NULL还会执行*pb != 0xff。
答:
为了查获程序员将“&&”误键入为“&”(或“||”误键为“|”)的情况,编译程序采用了与查获将“==”误键为“=”的同样测试。当程序员在if语句中或复合条件中使用了“&”(或“|”),并且没有明确地将结果与0进行比较时,编译程序将产生一个错误。所以见到下面这条语句会产生一个警告。
if ( u & 1 ) /* u是奇数吗?*/
而下面这条语句则不会产生警告信息。
if( (u & 1) != 0 ) /* u是奇数吗?*/
c)quot = numer/*pdenom。这里无意间多了个*号结果使/*被解释为注释的开始 。
答:
警告一个无意而误成为注释的最简单的方法是,当编译发现注释的第一个字符是字母或(时,发出一个警告。这样的测试将查获下面两个可疑情况:
quot = numer/*pdenom;
quot = number/*( pointer expression );
为了避免发出警告,你可以通过将“/”与“*”之间用空格或括号分开,使你的意图更明确。
quot = numer / *pdenom;
quot = number / (*pdenom);
/*注意:本注释将产生一个警告 */
/* 本注释不产生警告 */
/*----------------- 警告勿忧 -----------------*/
d)word = bHigh<<8 + bLow。由于出现了运算优先级错误,该语句被解释成了:wod = bHigh << (8 + bLow)
答:
编译查出可能存在的优先级顺序错的方法是,寻找在同一个不含括号的表达式中的“有麻烦的运算符对”。例如,当程序员偶然将“< <”和“+”运算符一起使用时,编译程序会发现优先级顺序错,对下面的代码发出警告:
word = bHigh << 8 + bLow;
但是,由于下面的语句含有括号,因此编译程序不发出警告信息:
word = ( bHigh << 8 ) + bLow;
word = bHigh << ( 8 + bLow );
如果不专设注释则可写警告式注释:“如果两个运算符具有不同的优先级顺序并没被括号括起,那么就要发出一个警告。”这样的注释太贫,但你在思想上要明白这点。开发一个好的启发式注释,需要在计算机上运行大量的代码直到最后产生有用的结果。你肯定不希望对下面这些常见的惯用语也产生警告信息:
word = bHigh * 256 + bLow ;
if ( ch == ‘ ’ || ch == ‘\t’ || ch == ‘\n’)
3、编译程序怎样才能对"没有与之配对的else"这一错误给出警告?用户怎样消除这一警告?
答:
当编译程序发现两个连续的if语句其后跟有一个else语句时,编译程序就会发出可能有悬挂else的警告信息:
if(expression 1)
if(expression 2)
……
else
……
if(expression 1)
if(expression 2)
……
else
……
为了避免编译程序发出警告信息,可以用括号将内层if语句括起:
if(expression1)
{
if(expression2)
……
}
else
……
if(expression1)
{
if(expression2)
……
else
……
}
4、在看一次下面的代码:
if('\t' == ch)
ExpandTab()'
这样如果应该键入==时键入了=,编译程序就会薄脆,因为不允许常量进行赋值。这个办法彻底么?为什么它不像编译程序开关自动化程度那么高?为什么新程序员会用赋值号代替等号?
答:
将常量和表达式置于比较操作的左边是很有意义的,它提供了自动检查错误的有一个方法。但时,这种方法必须有一个操作数是常量或表达式作为前提,如果两个操作数都是变量,这个方法就不起作用了。请注意,程序员在写代码的时候,一定要学会并记住使用这一技术。
通过使用编译开关,编译程序将警告每一种可能的赋值错。特别是对于没有经验的程序员,编译开关更显得特别有作用。
如果有编译开关,就一定要使用;如果没有,就把常量和表达式放在比较式的左边。
5、C的预处理程序也可能引起某些意想不到的结果。例如,宏UINT_MAX定义在limit.h中,但假如在程序中忘了include这个头文件,下面的伪指令就会无声无息地失败,因为
#if UINT_MAX > 65535u
.....
#endif
怎样使预处理程序报告出这一错误?
答:
为了防止误定义的预处理的宏产生不可预料的结果,编译(实际是预处理)程序应该具有一个开关允许程序员可以把无定义的宏用于错误情况。由于ANSI编译程序及支持老的#ifdef预处理指令,又支持新预处理的defined一元算子,那么就几乎没有必要将无定义的宏“定义”为0。以下代码将会产生错误:
/* 建立目标等式 */
# if INTEL8080
……
#elif INTEL80x86
……
#elif MC6809
……
#elif MC680x0
……
#endif
因此,应写为如下代码:
/* 建立目标等式 */
#if defined ( INTEL8080 )
……
#elif defined ( INTEL80x86 )
……
#elif defined ( MC6809 )
……
#elif defined ( MC680x0 )
……
#endif
如果在# ifdef语句中使用了无定义的宏,此开关不会给出警告,因为这是有意安排的。