这篇博客介绍了一种通过__COUNTER__
宏或__LINE__
宏来防止进入无限循环的方法。
该方法可以以一种透明的方式加入代码,在进行发行版编译的时候可以选择不对它进行编译。
原理
可能出现无限循环的地方,通常是一些依赖外部数据、外部脚本或者数据驱动的特定部分。由于外部数据的不可预测性,因此有必要对于无限循环的情况进行保护。
有一个实用的保护方法就是创建一个计数器,在每次循环的时候都进行+1,如果到达了某个极限的时候触发断言。
此时我们可以创建一个while_limit
宏,它与普通的while
循环差不多,唯一不同的就是有一个参数来定义循环次数的极限。当超过这个次数后,断言被触发。代码如下:
while_limit(node, 10000)
{
// Do your work
node = node->next;
}
while_limit
宏的实现
while_limit
宏的实现如下:
static bool while_assert( bool a )
{
assert(a && "while_limit: exceeded iteration limit");
return a;
}
#define UNIQUE_VAR(x) safety_limit ## X
#define _while_limit(a, b, c) \
assert(b > 0 && "while_limit: limit is 0 or less"); \
int UNIQUE_VAR(c) = b; \
while (a && while_assert(--UNIQUE_VAR(c) >= 0 ))
#define while_limit(a, b) _while_limit(a, b, __COUNTER__)
上面的代码使用了assert断言来进行提示,比起无休止的等待对开发人员更加友好。并且如果开发人员选择忽略掉这个断言,则while_limit
宏可以跳出这个循环而继续进行下面的流程。
__COUNTER__
宏与唯一变量
由于while_limit
可能会在多个地方展开,因此有必要给每一个地方的计数器都声明一个唯一变量。在代码中使用了__COUNTER__
宏,这个宏展开为一个整数,初始化为0,每使用一次就+1。
因此我们可以使用##
宏操作来进行唯一变量的创建,这个唯一变量可以用来跟踪循环次数。当第一次使用while_limit
宏的时候,计数器变量名为safely_limit0
,第二次则是safely_limit1
,这就保证了不会产生多重定义的问题。
由于__COUNTER__
宏在某些编译器里面编不过,因此实际上也可以使用另外的__LINE__
宏来进行唯一变量名的创建。
后记
这篇博客介绍的方法属于宏的奇技淫巧了,有的时候看到这些方法也的确会感到耳目一新。做个记录就好,希望以后的路不要走偏……