TRUE和FALSE宏的奇怪定义


300

我已经在编码书中看到以下宏定义。

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

那里没有解释。

请向我解释这些将如何TRUE和一起工作FALSE


63
我认为这是将TRUE定义为1并将FALSE定义为0的一种有趣方式
BlackDwarf

160
请注意,这是一个糟糕的主意,在这些表达式之间没有括号。我的意思是他们在一起是一个糟糕的主意,但没有您,您只是要求漫长的调试夜晚。
TartanLlama 2015年

70
我可以知道您正在参考的编码书吗?
artm 2015年

47
我希望本书将其作为不良或故意模糊代码的示例。
乔恩·汉娜

31
@Daniel:另一个想法是将rand()%2定义MAYBE为rand()%2,因此有时== TRUE,有时== FALSE。
Kaiserludi 2015年

Answers:


380

让我们看看:'/' / '/'表示char文字/,除以char文字'/'本身。结果为1,这听起来很合理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 ('-'-'-')

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


6
该死的,我花了很多时间来理解它:甚至认为它是一个很奇怪的
标志

8
与真值相乘实际上是有意义的。例如,缩进* should_indent将根据是否应无分支的should_indent得出0或缩进。(我想这是一个不好的例子,使用文本单分支无关紧要,(我已经在着色器和XPATH中看到了这种技术(两者都有很大的不同,我不记得确切的格式))
Alpedar

2
Alpedar-但在概念上和行为上都没有这样做的感觉-在这种情况下,使用a if而不是乘以TRUE整数会更清楚(从概念上讲是有意义的)。
周杰伦2015年

4
很好的解释。拥有金牌!
迈克尔·汉普顿

2
逻辑否定可能会实现notx = TRUE- x;并正常工作。除外TRUE-FALSE是-44(假设ASCII)
Hagen von Eitzen

89

这只是另一种写作方式

#define TRUE 1
#define FALSE 0

该表达式'/'/'/''/'自身的char值相除,结果为1。

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

define但是,缺少整个表达式的方括号,这可能会导致使用这些宏的代码出错。杰伊的答案说得很好。

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

#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


4
这个例子很好:)
Kit Fisto

44

相当于写作

#define TRUE 1
#define FALSE 0

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

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

最好写

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

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


5
大声笑!这就是为什么要对宏进行正确的括号化。
2015年

球面上的3个权利,您最终会在同一地方
Derek朕会功夫

@KerrekSB不行,但还有三个左手:)
蒂姆·隆

33

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

由于历史原因,这些表达式'/'/'/''-'-'-'来自的条目之一在1984年第一次国际C语言混乱代码大赛

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);}

(在此处链接到程序,在上面的IOCCC页面上有此程序的提示。)

另外,如果我没有记错这些表达式为模糊宏TRUEFALSE也涵盖在“混淆后的C和其他奥秘”的书由多恩·利伯斯(1993年)。


7

True和编写宏的有趣方式False

由于提供/了许多解释,意味着一个1字节的数字(按ASCII)除以它本身会给您1,它将被视为您,True同样地, -当减去它给您的相同值时又是一个字节数0,它将被解释为false

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

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

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

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


6

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

对于FALSE,其原因相同:'-'-'-'读取'-' - '-',即“ ASCII值'-'减去ASCII值'-'”,该值为0。因此,其FALSE值为0。

这是陈述显而易见的讨厌方法。


7
这与ASCII无关。
Kerrek SB 2015年

6
@Fabien:它不依赖于ASCII。'/'/'/'对于任何有效字符集,无论是'/' == 47(以ASCII形式),'/' == 97(以EBCDIC形式)还是其他任何值,均为1。
基思·汤普森

4
@Pawel:符合标准的C实现无法映射'/'0。该值保留为空字符。
基思·汤普森

2
您正在学究。
Matheus208

3
@ Matheus208如果Pawel在做修脚,那是('-'-'-'),因为他的观点是基于未声明的状态;将Keith的话描述为学究的话可能会更多('/'/'/'),但我称其为“澄清”(在我看来,加上笑脸的“学究的”肯定似乎是“ /'-'/”)。在一起的注释可能是('-'/'-'),可以称为pedantic,但是1)在该字段中不是不是一定要强制性的吗?2)他们让我思考;3)我在某些事情上比以前更加清楚。是的,我想我自己正在上学!(但我比我更清楚“学究”的含义!;-)
Zhora 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.