158 c precompiler
我见过C中的定义
#define TRUE (1==1)
#define FALSE (!TRUE)
Run Code Online (Sandbox Code Playgroud)
这有必要吗?简单地将TRUE定义为1,将FALSE定义为0有什么好处?
SLa*_*aks 153
如果编译器支持,此方法将使用实际boolean
类型(并解析为true
和false
).(具体来说,C++)
但是,最好检查C++是否正在使用(通过__cplusplus
宏)并实际使用true
和false
.
在C编译器中,这相当于0
和1
.
(请注意,删除括号会因操作顺序而中断)
Ada*_*iss 136
答案是便携性.的数值TRUE
和FALSE
并不重要.什么是重要的是,像声明if (1 < 2)
的计算结果为if (TRUE)
又像声明if (1 > 2)
评估为if (FALSE)
.
当然,在C中,(1 < 2)
评估1
和(1 > 2)
评估0
,正如其他人所说,就编译器而言,没有实际的区别.但是通过让编译器定义TRUE
并FALSE
根据自己的规则,你正在向程序员明确它们的含义,并且你保证程序和任何其他库的一致性(假设其他库遵循C标准......你会吃惊).
一些历史
一些基本定义FALSE
为0
和TRUE
作为-1
.像许多现代语言一样,它们将任何非零值解释为TRUE
,但它们评估的布尔表达式为真-1
.他们的NOT
操作是通过添加1并翻转符号来实现的,因为以这种方式执行它是有效的.所以'NOT x'成了-(x+1)
.这样做的一个副作用就是5
评估值TRUE
,但NOT 5
评估为-6
,这也是TRUE
!找到这种bug并不好玩.
最佳实践
鉴于事实上的规则将零解释为FALSE
并且任何非零值被解释为TRUE
,您永远不TRUE
FALSE
应该将具有布尔外观的表达式与or 进行比较.例子:
if (thisValue == FALSE) // Don't do this!
if (thatValue == TRUE) // Or this!
if (otherValue != TRUE) // Whatever you do, don't do this!
Run Code Online (Sandbox Code Playgroud)
为什么?因为许多程序员使用将int
s视为bool
s 的快捷方式.它们不一样,但编译器通常允许它.因此,例如,编写它是完全合法的
if (strcmp(yourString, myString) == TRUE) // Wrong!!!
Run Code Online (Sandbox Code Playgroud)
这看起来合法,编译器会乐意接受它,但它可能不会做你想要的.那是因为返回值strcmp()
是
0如果yourString == myString
<0 if yourString < myString
> 0 ifyourString > myString
所以上面的行TRUE
只返回yourString > myString
.
正确的方法是这样做
// Valid, but still treats int as bool.
if (strcmp(yourString, myString))
Run Code Online (Sandbox Code Playgroud)
要么
// Better: lingustically clear, compiler will optimize.
if (strcmp(yourString, myString) != 0)
Run Code Online (Sandbox Code Playgroud)
同理:
if (someBoolValue == FALSE) // Redundant.
if (!someBoolValue) // Better.
return (x > 0) ? TRUE : FALSE; // You're fired.
return (x > 0); // Simpler, clearer, correct.
if (ptr == NULL) // Perfect: compares pointers.
if (!ptr) // Sleazy, but short and valid.
if (ptr == FALSE) // Whatisthisidonteven.
Run Code Online (Sandbox Code Playgroud)
你会经常在生产代码中找到一些这些"不好的例子",许多有经验的程序员都会发誓:他们工作,有些比他们(迂腐?)正确的选择更短,而成语几乎被普遍认可.但要考虑:"正确"的版本效率并不低,它们保证可移植,即使是最严格的连接也会通过,甚至新程序员也会理解它们.
这不值得吗?
Kaz*_*Kaz 50
这个(1 == 1)
技巧对于以TRUE
对C透明的方式定义很有用,但在C++中提供了更好的输入.如果您使用名为"Clean C"(可编译为C或C++)的方言编写,或者您正在编写可供C或C++程序员使用的API头文件,则可以将相同的代码解释为C或C++.
在C翻译单元中,1 == 1
具有完全相同的含义1
; 并且1 == 0
具有相同的含义0
.但是,在C++翻译单元中,1 == 1
有类型bool
.因此TRUE
宏定义的方式更好地集成到C++中.
它如何更好地集成的一个例子是,例如,如果函数foo
有for int
和for 的重载bool
,那么foo(TRUE)
将选择bool
重载.如果TRUE
只是定义为1
,那么它在C++中将无法正常工作.foo(TRUE)
会想要int
超载.
当然,C99引入bool
,true
和false
与这些可以在与C99和与C.工作头文件中使用
然而:
TRUE
,并FALSE
为(0==0)
和(1==0)
早C99.如果您正在使用混合C和C++项目,并且不想要C99,请定义小写true
,false
而bool
不是.
#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif
Run Code Online (Sandbox Code Playgroud)
话虽如此0==0
,一些程序员甚至在代码中使用了诀窍,这些代码从未打算以任何方式与C++进行互操作.这不会买任何东西,并暗示程序员误解了布尔在C中的工作方式.
如果C++解释不明确,这是一个测试程序:
#include <cstdio>
void foo(bool x)
{
std::puts("bool");
}
void foo(int x)
{
std::puts("int");
}
int main()
{
foo(1 == 1);
foo(1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
bool
int
Run Code Online (Sandbox Code Playgroud)
关于如何重载C++函数与混合C和C++编程相关的注释中的问题.这些仅仅说明了类型差异.在编译为C++时想要一个true
常量的正当理由bool
是用于清洁诊断.在最高警告级别,如果我们将整数作为bool
参数传递,C++编译器可能会警告我们转换.在Clean C中编写代码的一个原因不仅在于我们的代码更具可移植性(因为C++编译器,而不仅仅是C编译器可以理解它),但我们可以从C++编译器的诊断意见中受益.
oua*_*uah 18
#define TRUE (1==1)
#define FALSE (!TRUE)
Run Code Online (Sandbox Code Playgroud)
相当于
#define TRUE 1
#define FALSE 0
Run Code Online (Sandbox Code Playgroud)
在C.
关系运算符的结果是0
或1
.1==1
保证被评估1
并!(1==1)
保证被评估0
.
绝对没有理由使用第一种形式.请注意,第一种形式的效率并不低于几乎所有编译器,在编译时而不是在运行时评估常量表达式.根据此规则允许这样做:
(C99,6.6p2)"可以在转换期间而不是运行时评估常量表达式,因此可以在常量可能的任何位置使用."
如果你不使用文字TRUE
和FALSE
宏,PC-Lint甚至会发出一条消息(506,常量值布尔值):
对于C,
TRUE
应该定义为1
.但是,其他语言使用的数量不是1,因此一些程序员认为这样做!0
是安全的.
同样在C99中,stdbool.h
布尔宏的定义true
和false
直接使用文字:
#define true 1
#define false 0
Run Code Online (Sandbox Code Playgroud)
sh1*_*sh1 12
除了C++(已经提到)之外,另一个好处是静态分析工具.编译器将消除任何低效率,但静态分析器可以使用自己的抽象类型来区分比较结果和其他整数类型,因此它隐式地知道TRUE必须是比较的结果,不应该被认为是兼容的用整数.
显然ç说,他们是兼容的,但你可以选择禁止故意使用该功能的帮助重头戏错误-例如,当某人可能有混淆&
和&&
,或者他们已经贻误了运算符优先级.