为什么在 C99 中 false 和 true 被定义为 0 和 1,而不是 ((bool)0) 和 ((bool)1)?

发布于 2024-11-19 06:31:11 字数 745 浏览 1 评论 0原文

我刚刚偶然发现了一个失败的断言,因为它将 false 与函数的返回类型进行了比较,因为函数本身返回了 bool,并且断言不仅检查了值,还检查了返回值的类型匹配 false ,保证返回一个 bool 值。

现在的问题是 C99 将 bool 定义为 _Bool 并且 _Bool 甚至不一定与int (事实上,根据我的经验,在当今的大多数平台上,它通常与 unsigned char 大小相同),更不用说是相同类型了(这实际上是不可能的,如 _Bool是 C99 中语言的内置类型),但将 false 和 true 定义为 0 和 1,没有任何类型转换和 没有类型转换的预处理器定义将默认为 int。

如果 C99 将 false 和 true 定义为 ((bool)0) 和 ((bool)1),则无论 _Bool 是如何定义的,它们将始终是 bool 类型。

那么,是否有充分的理由将它们始终定义为整数,即使 bool 在该平台上不是整数,或者这只是语言中的一个错误,应该使用 C1x

I just stumbled across an assert that failed, as it compared false to the returntype of a function, as the function itself returned a bool and the assert checked not only the value, but also the type of the returnvalue to match the one of false, to guarantee, that a bool is returned.

Now the problem is that C99 defines bool as _Bool and _Bool is even not necessarily the same size as int (in fact, in my experience, on most platforms nowadays, it is often the same size as unsigned char), not to talk about being the same type (which is actually impossible, as _Bool is a builtin type of the language in C99), but defines false and true as 0 and 1 without any typecast and preprocessor definitions without a typecast will default to int.

If C99 would instead define false and true as ((bool)0) and ((bool)1), they would always be of type bool, no matter, how _Bool is defined.

So is there a good reason to have them always defined as ints, even when bool is not an int on that platform or is this just a bug in the language that should be fixed with C1x?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

故乡的云 2024-11-26 06:31:11

falsetrue 分别定义为整数常量 01,因为这正是 C99 标准所指定的在7.16部分:

<截图>

其余三个宏适合在#if预处理指令中使用。他们

正确

扩展为整数常量 1,

扩展为整数常量 0,并且

<截图>

编辑:正如下面的评论所示,我似乎稍微误解了这个问题,我应该提供标准这样指定的原因。我能想到的一个原因是 truefalse 应该可以在 #if 预处理指令中使用(如标准中的引用)提到)。

((bool) 0)((bool) 1)#if 预处理指令中不起作用的原因是因为标准不允许。在 6.10.1 节中,它说:

控制条件包含的表达式应为整数常量表达式
不同之处在于:它不应包含强制转换;

false and true are defined as the integer constants 0 and 1 respectively, because that's exactly what the C99 standard specifies in section 7.16 :

< SNIP >

The remaining three macros are suitable for use in #if preprocessing directives. They
are

true

which expands to the integer constant 1,

false

which expands to the integer constant 0, and

< SNIP >

EDIT : as the comments below indicate, it seems I slightly misinterpreted the question, and I should have provided the reason the standard specifies it like that. One reason I can think of, is that true and false are supposed to be usable in #if preprocessing directives (as the quote from the standard mentions).

The reason ((bool) 0) or ((bool) 1) won't work in #if preprocessing directives, is because the standard doesn't allow it. In section 6.10.1 it says :

The expression that controls conditional inclusion shall be an integer constant expression
except that: it shall not contain a cast;

海未深 2024-11-26 06:31:11

除了已经提到的其他原因之外,因为只要您对 _Bool 执行了几乎任何操作,它就会变成 int

例如,(_Bool)0 & 的类型是什么? (_Bool)1?您可能认为表达式的类型为 _Bool,但实际上 §6.5.10 定义了 & 的语义:

...通常的算术转换是在操作数上执行的...

“通常的算术转换”在 C 标准中具有非常特定的含义。它在 §6.3.1.8 中定义,包括以下内容:

...对两个操作数都执行整数提升...

“整数提升”也是一个定义的术语,来自 §6.3.1.1:

如果int可以表示原始类型的所有值,则将该值转换为int;否则,它被转换为无符号整型。这些称为整数提升。48) 所有其他类型都不会因整数提升而改变。

尽管 C 标准中存在比 int 更窄的类型,但它们在几乎任何表达式中都会自动扩展为 int。再加上布尔运算的结果具有 int 类型这一事实,这使得 int 成为这些文字类型的自然选择。

Beyond the other reasons already mentioned, because a _Bool becomes an int anyway as soon as you do almost anything with it.

For example, what is the type of (_Bool)0 & (_Bool)1? You might think that the expression has type _Bool, but actually §6.5.10 defines the semantics of &:

... The usual arithmetic conversions are performed on the operands ...

"usual arithmetic conversions" has a very specific meaning in the C standard. It is defined in §6.3.1.8, and includes the following:

... the integer promotions are performed on both operands ...

"integer promotions" is also a defined term, from §6.3.1.1:

If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.48) All other types are unchanged by the integer promotions.

Although narrower types than int exist in the C standard, they are automatically widened to int in nearly any expression. Together with the fact that the result of the boolean operations has type int, this makes int a natural choice for the type of these literals.

魔法少女 2024-11-26 06:31:11

所有其他答案都试图使用该标准来证明为什么该标准以某种方式定义事物,我觉得这并不令人满意。该标准不仅定义了类型,还定义了运算符和预处理器,因此,如果 C99 引入了布尔类型,为什么不更改所有布尔运算符以计算该类型的值并扩展预处理器以支持布尔类型呢?

这样做是可能的,但需要更复杂。对于标准编写者和编译器编写者来说,只需进行最少的必要更改即可向语言添加新的布尔类型,这要容易得多。由于所有布尔运算仍然计算为 int 类型,因此所有 C99 之前的编译器都可以更新为支持 C99,而无需更改所有基本运算符的类型计算代码,并且标准编写者可以更加确信新的布尔功能不会意外地给标准中以前正常的部分带来不一致。他们所需要做的就是确保“通常的算术转换”应用于 _Bool,然后其他一切都可以保证正常工作。

这不是技术原因。这是一个实用的。

All the other answers are trying to use the standard to justify why the standard defines things a certain way, which I find unsatisfactory. The standard defines not only the types, but also the operators and the preprocessor, so if C99 was introducing a Boolean type, why not change all the Boolean operators to evaluate to a value of that type and extend the preprocessor to support Boolean types?

To do so would be possible, but more complicated the necessary. It was far easier for the standard-writers and the compiler-writers to make only the minimum necessary changes to add a new Boolean type to the language. Since all the Boolean operations still evaluate to type int, all the pre-C99 compilers can be updated to support C99 without having to change their type-evaluation code for all the basic operators, and the standard-writers can be more confident that the new Boolean feature hasn't accidentally introduced inconsistencies to parts of the standard that had previously been fine. All they needed to do was make sure the "usual arithmetic conversions" applied to _Bool, and then everything else is guaranteed to work.

It's not a technical reason. It's a practical one.

初与友歌 2024-11-26 06:31:11

首先,虽然 _Bool 可能不是 int,但要求 _Bool 可以接受值 0 和 1,因此扩展 truefalse 为 1 和 0 就可以了。

C99 §6.2.5/2:声明为 _Bool 类型的对象足够大,可以存储值 0 和 1。

此外,为了向后兼容,truefalse 合理地为 int,因为所有逻辑运算符都返回 int

C99 §6.5.3.3/5:逻辑非运算符 ! 如果其操作数的值不等于 0,则结​​果为 0,如果该值不等于 1,则结果为 1其操作数的比较等于 0。结果的类型为 int。表达式 !E 相当于 (0==E)

C99 §6.5.8/6:每个运算符 <(小于)、>(大于)、如果指定的关系为 true,则 <=(小于或等于)和 >=(大于或等于)应生成 1,如果为 true,则生成 0 false。90) 结果的类型为 int

C99 §6.5.9/3==(等于)和 !=(不等于)运算符是类似的关系运算符的优先级较低。91) 如果指定的关系为真,则每个运算符生成 1;如果指定的关系为假,则每个运算符生成 0。结果的类型为int。对于任何一对操作数,只有一个关系为真。

C99 §6.5.13/3:如果&& 运算符的两个操作数比较不等于 0,则其结果应为 1;否则,结果为 0。结果类型为 int

C99 §6.5.14/3:如果 || 运算符的任一操作数不等于 0,则其结果应为 1;否则,结果为 0。结果类型为 int

最后,如 @Sander De Dycker 提到,标准定义的 truefalse 可以这样扩展(C99 §7.16/3)。

Firstly, although _Bool may not be int, it is required that a _Bool can accept the values 0 and 1, therefore expanding true and false to 1 and 0 are fine.

C99 §6.2.5/2: An object declared as type _Bool is large enough to store the values 0 and 1.

Also, for backward compatibility, true and false are reasonable to be ints, because all logical operators return int.

C99 §6.5.3.3/5: The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int. The expression !E is equivalent to (0==E).

C99 §6.5.8/6: Each of the operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) shall yield 1 if the specified relation is true and 0 if it is false.90) The result has type int.

C99 §6.5.9/3: The == (equal to) and != (not equal to) operators are analogous to the relational operators except for their lower precedence.91) Each of the operators yields 1 if the specified relation is true and 0 if it is false. The result has type int. For any pair of operands, exactly one of the relations is true.

C99 §6.5.13/3: The && operator shall yield 1 if both of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.

C99 §6.5.14/3: The || operator shall yield 1 if either of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.

And finally, as @Sander De Dycker mentioned, the standard defined true and false be expanded like that (C99 §7.16/3).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文