C语言布尔表达式返回值



C语言没有布尔数据类型,而是使用整数。比较==和<=等操作符返回整数值0表示false, 1表示true。然而,C语言中的if语句认为其条件的任何非零值都等于true。为什么会有不同呢?为什么不允许关系运算符返回任何非零值来表示真呢?

我认为这是一个武断的决定,可以追溯到C的祖先语言b。

引用用户对B的引用:

关系运算符<(小于)、<=(小于等于)、>(大于)和>=(大于等于)采用整型右值操作数。如果操作数彼此处于给定的关系中,则结果为1。否则结果为零。

对于这个特殊的选择没有给出解释,在ANSI C基本原理或1978年Kernighan &里奇的书《C编程语言》(K&R1)。

(B语言的祖先语言BCPL有truefalse字面值,其中true的所有位都设置为1。)

语言可以有不同的定义,但它仍然是内部一致的。例如,标准可以规定,如果条件为假,关系和等式操作符产生0的结果,如果条件为真,则产生任意非零值。结果仍然可以在if语句或任何其他需要条件的上下文中正确使用。很容易想象,在一个CPU上,将真值表示为全位1比表示为1更有效,但语言标准不允许这样做。

一些标准库函数,如isdigit(),可以返回任意非零值来表示真条件,这进一步表明这是一个任意的选择。(isdigit自然是通过表查找实现的,它可以产生01以外的值)。

使用相等和关系操作符生成01增加了一些便利。例如,这使得计算有多少条件为真变得很容易:

int count = 0;
count += x == y;
count += foo > bar;
count += this <= that;

我的猜测是,在第一个B编译器中使用01是很方便的,这种行为被记录下来,并且它一直被继承到今天。更改定义会破坏依赖于先前定义的代码。

即使它在某些系统上相对低效,这也不是一个大问题。相等或关系运算符的结果通常不会存储在任何地方,因此编译器可以随心所欲地表示结果,只要行为一致即可。在某些情况下,它可能必须生成代码来将结果规范化为01,但这可能不是很重要。

如果条件表达式可以为true返回任何非零值,则在将其存储到太小的变量(在极端情况下是一个位域)时可能会遇到麻烦。

struct foo { unsigned int bar: 1; } baz;
baz.bar = 1 == 1;

如果1 == 1条件返回2(或任何偶数),你就有麻烦了,因为baz.bar最终会变成0,在布尔上下文中计算为false。

当您在条件中使用关系运算符时,编译器会将其编译为"大于则跳转"或类似的运算符,而不会实际计算<=表达式的返回值。表达式总是返回0或1并不重要,因为该值从未实际计算过。

关系操作符返回0或1的唯一情况是当它们的值用于较大的表达式时,例如算术运算或赋值给变量。这比直接在分支中使用它们的情况要少见得多,而且总是返回1的便利性代价并不高。

在C语言中,0为false,无论它是比较运算符或if语句的返回类型,还是您想要检查的任何类型。然而,虽然if()语句将接受任何不为零的true,但比较运算符必须只返回一个对象,因此决定该对象为'1'。这是你是接受还是拒绝的区别。

就像在任何其他函数中一样,比如int foo(int x){},你可以接受 x的任何值,但是你必须在离开函数之前选择你想要返回的值。我想你可以返回一个随机数,但那有什么用呢?

最新更新