我想定义一些基于常数值的函数:
#define mode 5
#if mode & 2 != 0
// function 1
#endif
#if mode & 4 != 0
// function 2
#endif
这听起来可能很奇怪,但我想用一个常量来定义和激活一些程序模块
定义mode = 2
包括函数1,mode = 4
包括函数2,mode = 6
同时包括这两个函数
有一个问题:像==
、!=
、>
或<
这样的比较运算符似乎在指令中不起作用,并且总是执行#if
语句。
我做错了什么?我是想做一件愚蠢或不可能的事吗?
&
的先验度低于!=
。因此:
MODE & 2 != 0
与相同
MODE & (2 != 0)
2 != 0
在逻辑上为真,因此!=
运算符的结果为1
。因此,这与相同
MODE & 1
它只是检查第一部分。当你想要:
(MODE & 2) != 0
检查第二位是否已设置。但实际上只需删除!=
部分并执行:
#if MODE & 2
记住,对于宏名称,更喜欢使用大写名称。
这听起来和看起来都很奇怪
不,这听起来完全正常。我会选择更多描述性的名字,然后简单的& 2
——神奇的数字会让人困惑。类似:
#define MODE (MODE_ENABLE_FUNC_1 | MODE_ENABLE_FUNC_2)
#define MODE_ENABLE_FUNC_1 (1<<0)
#define MODE_ENABLE_FUNC_2 (1<<1)
#define MODE_ENABLE_FUNC_3 (1<<2)
#define MODE_IS_ENABLED(mode, feature) ( ((mode) & (feature)) != 0)
#if MODE_IS_ENABLED(MODE, MODE_ENABLE_FUNC_1)
// etc.
如果可能的话,最好使用C++模板和SFINAE,而不是纯C宏。
我做错了什么?
您假设!=
的优先级低于&
。
我是想做一件愚蠢或不可能的事吗?
否。
我记得Dennis M.Ritchie的部分C语言的发展,从节名Neonatal C
开始,他写道:
[…]在从B到C的转换中,需要替换&由&;在该声明中;为了减少转换的痛苦,我们决定保留&运算符相对于==相同,并且仅拆分&;从&。今天,似乎最好将&和==,从而简化公共C习惯用法:要测试一个掩码值和另一个值,必须编写
if ((a&mask) == b) ...
其中需要内括号,但很容易忘记。
不用担心,您不是第一个也不是最后一个忘记&
和另一个运算符上下文中的大括号的人。