TRUE 和 FALSE 宏的奇怪定义

Posted

技术标签:

【中文标题】TRUE 和 FALSE 宏的奇怪定义【英文标题】:Strange definitions of TRUE and FALSE macros 【发布时间】:2016-03-07 20:47:22 【问题描述】:

我在一本编程书籍中看到过以下宏定义。

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

那里没有解释。

请向我解释这些将如何作为TRUEFALSE 工作。

【问题讨论】:

我认为将 TRUE 定义为 1 并将 FALSE 定义为 0 只是一种有趣的方式 请注意,如果这些表达式周围没有括号,这是一个糟糕的主意。我的意思是他们是一个糟糕的主意,但没有你只是要求调试一个漫长的夜晚。 我可以知道您参考的编码书吗? 我希望这本书将这个作为糟糕或故意模糊代码的示例。 @Daniel:另一个想法是将 rand()%2 定义为 rand()%2,因此有时 == TRUE,有时 == FALSE。 【参考方案1】:

这只是另一种写作方式

#define TRUE 1
#define FALSE 0

表达式'/'/'/' 会将'/' 的char 值除以自身,结果为1。

表达式'-'-'-' 将从自身中减去'-' 的char 值,结果为0。

但是,整个 define 表达式周围的括号都缺失了,这可能会导致使用这些宏的代码出错。 Jay's answer 讲得很好。

忘记括号可能有害的“现实生活”场景的一个示例是将这些宏与 C 风格的强制转换运算符结合使用。例如,如果有人决定在 C++ 中将这些表达式转换为 bool

#include <iostream>

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

int main() 
    std::cout << "True: " << (bool) TRUE << std::endl;
    std::cout << "False: " << (bool) FALSE << std::endl;
    return 0;

这是我们得到的:

True: 0
False: -44

所以(bool) TRUE 实际上会计算为false,而(bool) FALSE 会计算为true

【讨论】:

【参考方案2】:

相当于写

#define TRUE 1
#define FALSE 0

表达式'/'/'/'实际上所做的是将字符/(无论其数值是多少)除以自身,因此它变成1

类似地,表达式 '-'-'-' 从自身中减去字符 - 并计算为 0

最好写

#define TRUE ('/'/'/')
#define FALSE ('-'-'-')

避免在与其他优先级更高的运算符一起使用时意外更改值。

【讨论】:

【参考方案3】:

让我们看看:'/' / '/' 表示 char 文字 /,除以 char 文字 '/' 本身。结果是一个,这对于TRUE 来说是合理的。

'-' - '-' 表示从自身减去的char 文字'-'。这是零 (FALSE)。

这样做有两个问题:首先,它不可读。使用10 绝对更好。此外,正如 TartanLlama 和 KerrekSB 所指出的,如果您打算使用该定义,请在它们周围添加括号,这样您就不会感到意外:

#include <stdio.h>

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

int main() 
        printf ("%d\n", 2 * FALSE);
        return 0;

这将打印 char 文字 '-' 的值(在我的系统上为 45)。

带括号:

#define TRUE  ('/'/'/')
#define FALSE ('-'-'-')

该程序正确打印零,即使将真值乘以整数没有多大意义,但这只是一种意外错误的示例,如果您不给宏加上括号,可能会咬到您.

【讨论】:

乘以真值实际上是有意义的。例如 indentation*should_indent 将根据 should_indent 是否没有分支导致 0 或缩进。 (我想这是一个不好的例子,当使用文本单分支时并不重要,(我在着色器和 XPATH 中看到了这种技术(两者都太不同了,我不记得确切的形式)) Alpedar -- 但它在 概念上 和数学上没有这样做的意义 -- 在这种情况下,使用 @ 会更清晰(并且在概念上有意义) 987654337@ 而不是将TRUE 乘以一个整数。 逻辑否定可能被实现为notx = TRUE- x; 并且工作正常。除了 TRUE-FALSE 是 -44(假设 ASCII) @MarcWittke:嗯,那些滥用 C 预处理器和像这样损坏的宏的人很快就会失去朋友。众所周知,对没有用括号严格保护的事物进行简单的文本替换可能会造成极其不明显的破坏,这就是为什么 C++ 引入了这么多方法来没有 C 预处理器,例如模板和static const bool TRUE = true;。 (虽然这个定义实际上有int的类型,而不是bool。)【参考方案4】:

让我们从真实开始。你可以读成'/' / '/',意思是“字符'/'除以字符'/'”。由于 C 中的每个字符都是一个数值(在一个字节上),因此可以将其读取为“字符 '/' 的 ASCII 值除以同一字符的 ASCII 值”,这意味着 1(因为,显然, x/x 为 1)。因此,TRUE 为 1。

对于FALSE,其推理相同:'-'-'-' 读作'-' - '-',即“'-' 的 ASCII 值减去 '-' 的 ASCII 值”,即为 0。因此,FALSE 为0.

这是一种令人讨厌的方式来陈述显而易见的事情。

【讨论】:

这与ASCII无关。 @Fabien:它不依赖 ASCII。 '/'/'/' 是 1,表示 任何 个有效字符集,无论是 '/' == 47(在 ASCII 中),还是 '/' == 97(在 EBCDIC 中),或任何其他值。 @Pawel:符合标准的 C 实现无法将 '/' 映射到 0。该值是为空字符保留的。 @Pawel:当然,我本可以更明确一点。但由于问题是关于 C(和 C++)的,这就是我所说的“任何 valid 字符集”的意思。 @Matheus208 如果 Pawel 是迂腐的,那是 ('-'-'-') 因为他的观点是基于一个未说明的条件;将基思的言论描述为迂腐可能更多('/'/'/'),但我称它们为“澄清”(加上附加的笑脸,“迂腐”对我来说绝对是“/'-'/')。可能是 ('-'/'-') 将这些 cmets 放在一起可以称为迂腐,但是,1) 在这个领域不是有点强制性吗? 2)他们让我思考; 3)我对某些事情比以前更清楚了。是的,我想我自己也很迂腐! (但我比以前更清楚“迂腐”的含义!;-)【参考方案5】:

Jay 已经回答了为什么这些表达式的值是01

出于历史原因,这些表达式'/'/'/''-'-'-' 来自1st International Obfuscated C Code Contest in 1984 的条目之一:

int i;main()for(;i["]<i;++i)--i;"];read('-'-'-',i+++"hell\
o, world!\n",'/'/'/'));read(j,i,p)write(j/p+p,i---j,i/i);

(链接到程序here,上面的IOCCC页面中有这个程序做什么的提示。)

另外,如果我没记错的话,这些表达式作为 TRUEFALSE 的模糊宏也被 Don Libes (1993 年)的 "Obfuscated C and Other Mysteries" 所涵盖。

【讨论】:

【参考方案6】:

这是一种为TrueFalse 编写宏的有趣方式。

由于提供了许多解释,/ 表示一个 1 字节的数字(根据 ASCII),当它自己除以它给你 1 将被视为 True 并且同样- 再次是一个字节减去相同值时的数字,它给你0,这将被解释为false

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

因此我们可以将/- 替换为我们喜欢的任何字符,例如:

#define TRUE  '!'/'!'
#define FALSE 'o'-'o'

将保持与原始表达式相同的含义。

【讨论】:

以上是关于TRUE 和 FALSE 宏的奇怪定义的主要内容,如果未能解决你的问题,请参考以下文章

Variadic Macros:如何解决“宏的实际参数过多..”

JSF 中的 render=true/false 问题的奇怪问题

10-cmake语法-函数和宏的定义

带有upload_files true但edit_post false的Wordpress自定义用户角色,我如何删除和编辑媒体?

null,undefined,true,false,以及== 和===

如何定义只有一个字段写入特定节点?