20

在 C 项目中(OpenVPN 是有问题的项目,提交4029971240b6274b9b30e76ff74c7f689d7d9750)我们模拟了 bool

typedef int bool;
#define false 0
#define true 1

现在切换到 C99 bool

#include <stdbool.h>

但是在项目中,布尔值在某处使用不当。我知道 std bool 的行为不同。例如

bool t;

t=2;
if ( t == true)
    printf("True!\n");
else
    printf("False!\n");

将返回真!和stdbool.h假!与#define仿真。

我的问题有没有办法找到这些与 stdbool 和仿真 bool 表现不同的代码部分?也许我忽略了一些编译器标志或可以区分的良好 llvm 或 gcc 中间格式?

它不像上面的例子那么简单,但必须是不那么容易看到的东西。绝对不是a == true。

更新: 我们发现了问题(mbuf_set 有一个 int 成员 len)。这有点愚蠢,但问题仍然是如何抓住这些。我很惊讶整数溢出检查没有捕捉到这样的事情:

 static inline bool
 mbuf_len (const struct mbuf_set *ms)
 {
   return ms->len;
 }
4

1 回答 1

2

您描述的这种用法是正确的,定义明确的行为。所以编译器不会产生任何警告。解决此问题的一种可能方法是更改typedef​​:

typedef enum {false, true} bool;

这仍将允许代码无错误地编译(因为它已明确定义),但您可以强制来自编译器或分析器的警告。例如,clang将选择这种事情-Weverything

$ clang -o a a.c -Weverything
a.c:7:11: warning: integer constant not in range of enumerated type 'bool'
      [-Wassign-enum]
        bool n = 2;

当然,这不会进行任何运行时检查。它仍然允许将typedefbool 变量更改为 0 或 1 以外的值(例如,通过函数调用或表达式)。检测这些实例的唯一方法是使用调试器。

true 和 false in 的宏stdbool.h实际上仅针对该_Bool类型而设计。这是因为这种类型只能保存值 0 和 1;您分配的任何不是 0 的值都存储为 1。因此,仅对于布尔类型,true 和 false 宏保证可以工作。

如果没有_Bool类型,就无法让语言本身直接为您执行此操作,因为没有可比较的类型,您实际上会要求它允许2 == 1返回 true。

有几种方法可以实现相同的行为,例如BOOL(n)在使用变量的每个实例中使用宏n,以确保其值仅为 0 或 1。这样,无论使用_Bool还是intfor ,您都会得到相同的结果n。例如:

#define BOOL(n) ((n) != 0 ? 1 : 0 )

bool b = rand() % 100;

if (BOOL(b) == true) ...

无论是使用stdbool还是使用typedef.

于 2013-03-11T13:32:43.400 回答