在一个C项目(OpenVPN是有问题的项目,提交4029971240b6274b9b30e76ff74c7f689d7d9750)我们有一个模拟bool
typedef int bool;
#define false 0
#define true 1
Run Code Online (Sandbox Code Playgroud)
现在切换到C99布尔
#include <stdbool.h>
Run Code Online (Sandbox Code Playgroud)
但在该项目有地方的布尔的一个不好的用法.我知道std bool表现不同.例如
bool t;
t=2;
if ( t == true)
printf("True!\n");
else
printf("False!\n");
Run Code Online (Sandbox Code Playgroud)
将返回True!与stdbool.h
和假的!与#define
模拟.
我的问题有没有办法找到这些与stdbool和模拟bool行为不同的代码部分?也许有些编译器标志我忽略了或者是一个好的llvm或gcc中间格式可以被区分?
它没有上面例子那么简单,但必须是不容易看到的东西.绝对不是== true.
更新: 我们发现了问题(mbuf_set有一个int成员len).这有点愚蠢,但问题仍然是如何抓住这些.我很惊讶整数溢出检查不会捕获这样的事情:
static inline bool
mbuf_len (const struct mbuf_set *ms)
{
return ms->len;
}
Run Code Online (Sandbox Code Playgroud)
您所描述的用法是正确的、定义明确的行为。所以编译器不会产生任何警告。解决这个问题的一种可能的方法是更改typedef
:
typedef enum {false, true} bool;
Run Code Online (Sandbox Code Playgroud)
这仍然允许代码编译而不会出现错误(因为它定义良好),但您可以强制编译器或分析器发出警告。例如,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;
Run Code Online (Sandbox Code Playgroud)
当然,这不会进行任何运行时检查。它仍然允许将typedef
bool 变量更改为 0 或 1 以外的值(例如通过函数调用或在表达式中)。检测这些实例的唯一方法是使用调试器。
true 和 false in 的宏stdbool.h
实际上只是针对该_Bool
类型而设计的。这是因为该类型只能保存值 0 和 1;您分配的任何非 0 值都将存储为 1。因此,仅对于布尔类型,true 和 false 宏保证有效。
如果没有_Bool
类型,就无法让语言本身直接为您执行此操作,因为没有可比较的类型,并且您实际上会要求它允许2 == 1
返回 true。
有几种方法可以实现相同的行为,例如,BOOL(n)
在使用变量 的每个实例中使用宏n
,以确保其值仅为 0 或 1。这样,无论使用_Bool
还是int
for ,您都会得到相同的结果n
。例如:
#define BOOL(n) ((n) != 0 ? 1 : 0 )
bool b = rand() % 100;
if (BOOL(b) == true) ...
Run Code Online (Sandbox Code Playgroud)
无论使用stdbool
还是typedef
.