【问题标题】:Strange definition of FALSE and TRUE, why? [duplicate]FALSE 和 TRUE 的奇怪定义,为什么? [复制]
【发布时间】:2013-10-21 23:14:11
【问题描述】:

在我正在编写的一些代码中,我遇到了对真假的奇怪重新定义。我以前见过这样的事情,以使检查更加严格/确定,但这在我看来有点奇怪,我想知道是否有人可以告诉我这样定义的充分理由,请参阅下面的我的 cmets 他们旁边:

#define FALSE (1 != 1) // why not just define it as "false" or "0"?
#define TRUE (!FALSE)  // why not just define it as "true" or "1"?

这个代码库中还有许多其他奇怪的东西。就像所有标准类型都有重新定义一样:

#define myUInt32 unsigned integer // why not just use uint32_t from stdint?

所有这些小“怪癖”让我觉得我错过了一些明显的东西,但我真的看不出重点:(

注意:严格来说,这是 c++ 代码,但它可能是从“c”项目移植而来的。

【问题讨论】:

  • 这样的定义有时用于获得源代码的可移植性,不仅在不同的 C++ 编译器之间(可能在不同的平台上),甚至在 C 编译器和 C++ 编译器之间。
  • 0相比,如果编译器支持bool类型,1!=1具有正确的类型。
  • 您可能至少缺少以下一些东西的组合:标准前遗留代码、NIH 综合症和愚蠢。
  • 我从这个问题得到了一些非常好的反馈! - 非常感谢所有对所有好的/有用的答案的 +1 :)
  • @devnull 是的,它非常相似,我想我错过了它,因为我的定义更多是在“错误”方面:(,但仍然......很好的答案谢谢大家!

标签: c++ c boolean


【解决方案1】:

意图似乎是可移植性

#define FALSE (1 != 1) // why not just define it as "false" or "0"?
#define TRUE (!FALSE)  // why not just define it as "true" or "1"?

这些在支持它的语言中具有布尔类型 (C++),同时为不支持的语言提供仍然有用的数值(C — 甚至 C99 和 C11,显然,尽管它们获得了显式布尔数据类型)。

尽可能使用布尔值有利于函数重载。

#define myUInt32 unsigned integer // why not just use uint32_t from stdint?

如果stdint 可用,那很好。你可能认为这样的事情是理所当然的,但那里是一个广阔的世界!这段代码可以识别。

免责声明:就个人而言,我坚持标准,并简单地声明 1990 年以后发布的编译器是先决条件。但我们不知道所讨论项目的基本要求是什么。

TRWTF 是有问题的代码的作者并没有在旁边的 cmets 中解释这一点。

【讨论】:

  • 即使在 C11 中,!=! 运算符的结果也是 int 类型,而不是布尔值。
  • @DavidHammen C11 不是 C++11。
  • @R.MartinhoFernandes - 你是对的。我忘记了 C 和 C++ 都带有 2011 版本的标准。我删除了我的评论。不过值得一提的是,在 C++ 中,原始布尔运算符的结果确实是bool,而不是int
  • 注意:1979-1998 C++ 不一定有类型bool。同意“声明 1990 年以后发布的编译器是先决条件”。像if (!!x) 这样的构造在当时很常见。
  • WTF是TRWTF是什么意思?
【解决方案2】:
#define FALSE (1 != 1) // why not just define it as "false" or "0"?

我认为这是因为表达式(1!=1)类型取决于语言对布尔值的支持——如果是C++,类型是bool,否则是int .

另一方面,0 在两种语言中总是int,而false 在 C 中不被识别。

【讨论】:

    【解决方案3】:

    严格来说,这是 c++ 代码,但它可能是从“c”项目中移植而来的。

    这与前面提到的可移植性有关,但实际上远不止于此。这是对语言定义的巧妙利用以符合语言

    这些看起来很荒谬的宏并不像乍一看那么荒谬,但实际上它们很巧妙,因为它们保证了 C 和 C++ 的 TRUEFALSE 具有正确的值(和类型) truefalse(即使编译器是没有这些关键字的 C 编译器,所以你不能随便写像 #define TRUE true 这样的东西)。

    在 C++ 代码中,这样的结构是没有用的,因为该语言将 truefalse 定义为关键字。
    但是,为了让 C 和 C++ 在同一代码库中无缝互操作,您需要适用于两者的“某种东西”(除非您想使用不同的代码风格)。

    这些宏的定义方式证明了 C++ 标准对 truefalse 实际具有的值明确含糊不清。 C++ 标准规定:

    bool 类型的值为真或假。
    [...]
    零值、空指针值或空成员指针值转换为假;任何其他值都将转换为 true。
    [...]
    bool 类型的纯右值可以转换为 int 类型的纯右值,false 变为 0,true 变为 1。

    请注意它是如何说明存在两个特定值的,它们的名称是什么,以及它们相互转换的对应整数值是什么,但它没有说明这些值是什么。您可能倾向于认为这些值显然是 01(并且顺便您可能猜对了),但事实并非如此。故意没有定义实际值。

    这类似于指针(尤其是空指针)的定义方式。请记住,零整数文字转换为空指针,空指针转换为false,比较等于...等等等等。
    关于哪个转换为什么和什么什么的说法很多,但它没有说空指针必须具有零的二进制表示(事实上,存在一些奇特的架构,其中事实并非如此!)。

    【讨论】:

    • 这是一个多源成语。在应用程序源代码在 Pascal、C 和多个汇编器之间拆分的环境中,我们使用了非常类似的东西来防止愚蠢的错误。这是表达“真实性”(窃取科尔伯特主义 )的一种自然技巧,因为每种语言都有不同的 TRUE 和 FALSE 数字版本。
    【解决方案4】:

    其中很多有历史原因,比如从 C 移植过来的旧代码、来自非标准 C++ 编译器的代码、交叉编译器代码(可移植性)、支持向后兼容、遵循代码风格、不良习惯。

    有些编译器没有<cstdint> 来处理像uint32_t 这样的整数类型,或者他们没有<cstdbool>。一个优秀的程序员必须定义一切并大量使用预处理器,以使他的程序在不同的编译器上得到很好的定义。

    今天,我们可以使用<cstdint>true/false<cstdbool>,......每个人都很开心!

    【讨论】:

      【解决方案5】:

      这个定义的好处是避免了从 TRUE 或 FALSE 到整数的隐式转换。这有助于确保编译器不会选择错误的函数重载。

      【讨论】:

        【解决方案6】:

        C 没有本机布尔类型,因此您不能严格使用“false”或“true”而不在其他地方定义它们 - 那么您将如何定义它?

        同样的论点适用于 myUInt32 - C 最初没有 uint32_t 和 stdint 中的其他类型,因此这提供了一种确保您获得正确大小整数的方法。如果您移植到不同的架构,您只需将 myUInt32 的定义更改为等于 32 位宽的无符号整数 - 无论是长整数还是短整数。

        【讨论】:

          【解决方案7】:

          有一个很好的解释说明了 false 和 FALSE 之间的区别。我认为这可能有助于进一步理解,尽管大多数答案都已经解释过了。 here

          【讨论】:

            猜你喜欢
            • 2016-03-07
            • 1970-01-01
            • 2021-11-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-09-30
            • 1970-01-01
            • 2019-02-08
            相关资源
            最近更新 更多