C语言基本功修炼秘籍第6节,C语言有原生的布尔类型吗?自己将TRUE定义为1安全吗?

C语言程序开发是离不开条件判断语句的,有程序员甚至认为编程其实就是 if else 再加上一点数学计算。不过,对于计算机来说,条件判断结果只有两个可能值:真 或者 假。

C语言认为所有非零值都是“真”,零值为“假”,虽然很简单,但是从读者向我反馈的问题来看,这中间仍然有一些让初学者迷惑的地方,为此,本节将以问答形式讨论一下C语言程序开发中的布尔值以及相关表达式。

C语言中有标准的布尔(Boolean)类型吗?

首先来说说什么是布尔类型。狭义来看,布尔类型是只有“真”和“假”两个可能值的类型,鉴于目前计算机只认识 0 和 1,这里认为布尔类型只有 0 和 1 两个可能值的类型。

经典C语言是没有提供标准布尔类型的,程序员如果希望使用布尔类型,一般都是使用其他数据类型代替,比如 int ,char ,枚举等类型,或者干脆直接使用 0 和 1:

#define        TRUE    1
#define        FALSE   0

#define        bool    int

#define        bool    char

enum bool {false, true};

一般来说,使用 int 类型程序的效率更高一些,而使用 char 类型,程序消耗的内存空间更小一些。当然了,如果读者的调试器能够显示枚举名,枚举类型可能更方便于开发调试。

也有程序员更加偏爱下面这种定义方式,请看:

#define TRUE (1==1)
#define FALSE (!TRUE)

值得说明的是,C99 增加了_Bool关键字,使得C语言有了自己的布尔类型。C99 新增了标准头文件 <stdbool.h>,它的内容很简单,相关C语言代码如下,请看:

包含<stdbool.h>头文件后,就可以使用 bool 定义布尔类型变量了,例如:

#include <stdbool.h>
bool b;
b = true;
b = false;

上述C语言代码中的变量 b 即为布尔类型,它只能存储 0 或者 1。下面是较为完整的使用示例:

#include <stdbool.h>
#include <stdio.h>

int main()
{
    bool test;

    test = 0;
    test = 1;
    test = 2;

    printf("sizeof(bool)=%lu, test=%d\n", sizeof(bool), test);

    return 0;
}


编译并执行这段C语言代码,得到如下输出:

# gcc t3.c
# ./a.out 
sizeof(bool)=1, test=1

可见,编译器是允许使用除 1 外的其他非零值对布尔类型变量 test 赋值的,但是最终编译器会将该非零值转换为 1。另外,bool 类型也要占用 1 字节的内存空间。

在C语言程序开发中,将 TRUE 定义为 1 危险吗?

有读者问我,既然C语言将“所有非零值”都当作“真”,那么在程序中将 TRUE 定义为 1 会不会有局限性呢?

读者有这样的顾虑,应该是考虑到了“不同的真值”对比将得到错误答案。例如同为真的值 3 和 8,却不能像 “真==真”这样对比,因为“3==8”明显是“假”的,C语言中的真假值好像有些混乱。

C语言的确将所有非零值都当作“真”,但是这仅适用于“输入”时,即需要布尔值的地方。诸如 ==, !=, < 等逻辑运算符处理后的布尔值必定是 0 或者 1,因此像:

if( (a==b)==TRUE )

这样的C语言代码必定可以正常工作,但是这样写代码无疑是愚蠢的。事实上,在C语言程序中,直接比较真假值的确非常危险,再举例来说,某些库函数(如 isupper(), isalpha() 等)成功时返回的是非零值,不一定是 1,下面这样的C语言代码就比较危险了:

if(isupper(...)==TRUE)

可能得不到正确的判断结果。所以,在C语言程序开发中,将 TURE 定义为 1 危险不危险,取决于程序员的使用方式。我比较推荐只将 TRUE 这样的定义值做赋值用,或者做布尔函数的返回值,应该特别小心用其做比较。

如果必须要比较布尔值,我在C语言程序开发中,常使用的一个小技巧是使用 !!,例如 if( (!!a) == (!!b) ),原因留给读者自己考虑了。

有程序员认为:

if( (a==b)==TRUE )

是下面这种写法的提升,程序将更加安全:

if( a==b )

如果真的是这样,为什么只写一个 TRUE,不多写几个呢?

if( (((a==b)==TRUE)==TRUE)==TRUE )

需要判断 p 是否真的时候,直接写 if(p) 会丢失可移植性吗?如果 p 是指针呢?

当然是可以直接写成 if(p) 。如果 p 不等于 0,那么C语言将认为 if(p) 成立,否则认为 if(p) 不成立。事实上,C语言编译器会将 if(p) 等同于 if( p!=0 )。

可能读者已经知道,C语言中的空指针值有时候并不等于 0。那么,此时 if(p) 还能成功判断 p 是否空指针吗?答案是肯定的。C语言编译器比较聪明,它在处理代码时是会考虑上下文的。

以 if(p) 为例,其等同于 if(p!=0),编译器发现 p 是一个指针,于是会进一步将 0 看作是空指针,替换成相应的空指针值,所以即使 p 是指针,if(p) 仍然能够正常工作。

小结

C语言认为“所有非零值都为真”,这造成了一些初学者理解布尔值的混乱,好在C99提供了原生的布尔类型。不过,如果读者在不支持C99的平台开发程序,只能自定义布尔类型及布尔值,可以考虑遵守本节提供的经验:只将 TRUE 这样的定义值做赋值用,或者做布尔函数的返回值,而尽量避免直接与其他布尔值对比。

阅读更多:   C语言
添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif