捕捉C语言bool类型的错误用法

20

在一个C项目中(OpenVPN是涉及的项目,提交4029971240b6274b9b30e76ff74c7f689d7d9750),我们有一个bool的仿真。

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

现在切换到 C99 的 bool 类型

#include <stdbool.h>

但是在项目中,某处使用了错误的bool。我知道标准bool的行为不同。例如:
bool t;

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

使用 stdbool.h 会返回 True!使用 #define 模拟将返回 False!

我的问题:有没有办法找到这些代码部分,它们在使用 stdbool 和模拟 bool 时表现不同?也许我忽略了一些编译器标志或者可以进行 diff 的好的 llvm 或 gcc 中间格式?

这不像上面的示例那么简单,必须是一些不容易看出来的东西。绝对不是 a == true。

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

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

5
只需查找布尔字面量;直接与 truefalse 进行比较的代码会有问题。使用更好(在我看来)的方法,只需编写 if( t ) 就可以了。你可以搜索 true|false ,然后通过 == 的命中结果进行过滤。 - unwind
3
一种可能的方法是使用枚举类型替代宏定义。然后,让一个静态代码分析器解析你的代码,并检查诸如“t=2”之类的错误。但这将包括所有代码,例如“t=1”。 - Argeman
尝试编写函数getTruegetFalse,它们将返回调用次数。之后,您可以搜索numberGetTrue == quantity true来确定是否为真。 - Dmitry Zagorulkin
如果您可以使用C++编译器进行编译,请尝试创建一个名为check_bool的类,该类具有对bool的隐式转换。覆盖==运算符,=运算符(对于int使其为私有,对于check_bool使其为公共)。然后#define bool check_bool。还要将true和false定义为该类的对象。 - Aneri
@KeithThompson 这正是 PCLint(例如)所做的。 - Argeman
显示剩余6条评论
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;

当然,这并不会进行任何运行时检查。它仍然允许将 typedef 布尔变量更改为除0或1之外的其他值(例如通过函数调用或在表达式中)。唯一检测这些情况的方法是使用调试器。

stdbool.h 中的 true 和 false 宏主要设计用于 _Bool 类型。因为此类型只能容纳值0和1;您分配的任何非0值都将存储为1。所以对于布尔类型,true 和 false 宏是保证有效的。

如果没有 _Bool 类型,则没有办法让语言直接为您执行此操作,因为没有可比较的类型,您实际上正在请求它允许 2 == 1 返回 true。

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

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

bool b = rand() % 100;

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

这将适用于使用 stdbooltypedef 的情况。

我知道逻辑已经改变了。我不想模拟新的布尔值。我想找出为什么代码不能使用stdbool。 - plaisthos
@plaisthos 因为没有 stdbool,所以 if ( t == true)if ( 2 == 1) 是一样的。 - teppic
请重新阅读我的问题。我的示例仅用于演示逻辑不同。 - plaisthos
我不想实现相同的行为。我想找到因不同行为而表现不同的代码部分。添加 #define BOOL 对我没有帮助,因为我必须更改涉及布尔变量的每个 if 语句。 - plaisthos
@plaisthos - 我已经添加了答案,以便提供获取该信息的想法。 - teppic
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接