《 C 语言的一些“骚操作”及其深层理解》之隐藏的死循环
扫描二维码
随时随地手机看文章
隐藏的死循环
有些时候我们会发现for循环变成了一个死循环:
unsigned char i;
for(i=4;i>=0;i--) ....
我们本希望循环5次,然后结束,但是实际情况是陷入了死循环。这种错误在实际开发中,还比较难发现。其原因在于i的类型,无符号整型是永远不小于0的。我们需要将i的类型改为有符号型。
signed char i;
for(i=4;i>=0;i--) ....
OK,这样就对了。细节虽小,但是对实际开发的影响还是蛮大的,请大家引以为戒。
下面的两个例子中for循环也是死循环,请自行分析:
例1:
unsigned char i;
for(i=0;i<256;i++) ...
提示:i的数据类型。
例2:
char str[20];
char *p;
unsigned char n=0;
for(p=strcpy(str," abcd");((*p)=' ');p++,n++);
提示:这个例子,不光会死循环,而且还可能会让程序直接崩溃。判等的==你会不会经常直接写错成=(赋值表达式)。
看似多余的空循环
有时我们会看到这样的代码:
do
{
...... //do something
}while(0);
代码本身实际只运行了一次,为什么要在它外面加一层do while呢?这看似是多余的。其实不然,我们来看下面例子:
#define DO_SOMETHING fun1();fun2();
void main(void)
{
while(1) DO_SOMETHING;
}
while(1) DO_SOMETHING;本意应该是不断调用fun1和fun2,但实际上只有fun1得到运行。其中原因大家应该明白。所以,我们可以这样来写:
#define DO_SOMETHING do{ fun1();fun2();}while(0);
do while就如同一个框架把要运行的代码框起来,成为一个整体。
独立执行体
我在C语言编程的过程中,经常乐于使用一种“局部独立化”的方式,我称之为“独立执行体”,如下例:
void fun(int a,int b,int c)
{
Int tmp=0;
//主体计算
{ //独立执行体,解决临时性问题
int c=0;
c=(a>b)?a:b;
printf("max:%d\r\n",c);
}
{ //独立执行体
int c=0,d=0,.....,res=0.;
//数据处理算法
printf("result:%d\r\n",res);
}
//进一步计算
}
编程时,我们经常需要解决一些小问题,比如想对一些数据进行临时性的处理,查看中间结果;或是临时性的突发奇想,试探性的作一些小算法。这过程中可能需要独立的变量,以及独立于主体程序的执行逻辑,但又觉得不至于去专门定义一个函数,只是想一带而过。比如上例,函数fun主要对a、b、c这3个参数进行计算(使用某种算法),过程中想临时看一下a和b谁比较大,由第一个“独立执行体”来完成,其中的代码由自己的{}扩起来。
其实我们可以更深层的去理解C语言中的{},它为我们开辟了一个可自由编程的独立空间。在{}里,可以定义变量,可以调用函数以及访问外层代码中的变量,可以作宏定义等等。平时我们使用的函数,它的{}部分其实就是一个“独立执行体”。
“独立执行体”的思想,也许可以让我们编程更加灵活方便,可以随时让我们直接得到一块自由编程的静土。
上一节中的do while(0),其实完全可以把do while(0)去掉,只用{}即可:
#define DO_SOMETHING {fun1();fun2();}
其中它还有一个好处,就是当你不需要这段代码的时候,你可以直接在{}前面加上if(0)即可。一个“独立执行体”的外层是可以受if、do while、while、for等这些条件控制的。