【问题标题】:Catch incorrect usage of c bool捕获 c bool 的错误用法
【发布时间】:2023-12-01 11:08:01
【问题描述】:

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

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

现在切换到 C99 bool

#include <stdbool.h>

但是在项目中 somewhere 对 bool 的使用不好。我知道 std bool 的行为不同。例如。

bool t;

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

将返回 True! stdbool.h 和 False!使用#define 仿真。

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

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

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

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

【问题讨论】:

  • 只搜索布尔字面量;与truefalse 进行比较的代码实际上会有问题。使用(更好,imo)方式的代码只是说if( t ) 就可以了。您或许可以搜索true|false,然后按== 的点击次数对其进行过滤。
  • 一种可能性是使用枚举而不是定义。然后,让静态代码分析器解析您的代码并检查诸如“t=2”之类的错误。但这会产生任何代码,包括“t=1”之类的代码。
  • 尝试编写函数getTruegetFalse,这将返回调用次数。在您可以搜索 numberGetTrue == 数量 true 之后。
  • 如果您可以使用 C++ 编译器进行编译,请尝试创建一个具有隐式转换为 bool 的类 check_bool。覆盖 == 运算符,= 运算符(对于 int 将其设为私有,对于 check_bool 将其设为公开)。然后#define bool check_bool。还要对这个类的对象定义真假。
  • 我知道它不是 C++,但 C 有时可以由 C++ 编译器编译。这是一个测试编译,用于查看 int 在何处分配/与 bool 值进行比较。

标签: c c99


【解决方案1】:

您所描述的这种用法是正确的、定义明确的行为。所以编译器不会产生任何警告。解决此问题的一种可能方法是更改​​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 bool 变量更改为 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) ...

无论使用stdbool 还是typedef,这都可以工作。

【讨论】:

  • 我知道逻辑变了。我不模仿新的布尔。我想找出为什么代码不能与 stdbool 一起使用
  • @plaisthos 因为没有stdboolif ( t == true)if ( 2 == 1) 相同。
  • 请重新阅读我的问题。我的例子只是为了证明逻辑不同
  • @plaisthos - 对于t 不等于 1 的任何情况都是如此。逻辑没有什么不同,只是 _Bool 不能是 0 或 1 以外的任何值。
  • 我不想实现相同的行为。我想找到由于行为不同而表现不同的代码部分。添加 #define BOOL 对我没有帮助,因为如果涉及 bool 变量,我将不得不更改每一个。