【问题标题】:Using Comparison Operators in preprocessor directives C++在预处理器指令 C++ 中使用比较运算符
【发布时间】:2020-10-26 14:25:15
【问题描述】:

我想根据一个常数值定义一些函数:

#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 语句。

我做错了什么?我是在尝试做一件愚蠢或不可能的事情吗?

【问题讨论】:

  • “似乎在指令中不起作用,只是被忽略了” - 不清楚你在这里的意思。一般来说,“不起作用”不是一个有用的问题陈述。请修改您的minimal reproducible example 以准确说明问题所在。如果有错误,请逐字复制。如果它运行但做错了事,请说出您的期望以及实际发生的情况。
  • mode & 2 != 0 不是(mode & 2) != 0
  • 在这种情况下,为了避免问题,我更喜欢使用constexpr int mode = 5;等。
  • FWIW,另一种不使用预处理器的方法是使用 template <int N> void my_function_set(...); 之类的模板,然后将其专门用于 N 的不同值,然后您将只需 my_function_set<constant>(...) 在呼叫站点。
  • @Damien - 你可以使用constexpr,但是你会遇到它在条件编译中完全没用的问题。 C++ 可能已经大大减少了对预处理器的需求,但它还没有取代它的所有用途(目前)。

标签: c++ arduino c-preprocessor directive comparison-operators


【解决方案1】:

&precendence 低于 !=。所以:

MODE & 2 != 0

一样
MODE & (2 != 0)

2 != 0 在逻辑上为真,所以!= 运算符的结果是1。因此,这与

MODE & 1

它只是检查第一位。随心所欲:

(MODE & 2) != 0

检查是否设置了第二个位。但实际上只需删除 != 部分并执行以下操作:

#if MODE & 2

记得prefer upper case names for macro names

这听起来和看起来很奇怪

不,这听起来很正常。我会使用更多描述性的名称,然后简单的 & 2 - magic numbers 会令人困惑。喜欢:

#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 宏。

我做错了什么?

您假设!= 的优先级低于&amp;

我是在尝试做一件愚蠢或不可能的事情吗?

没有。


我记得 The development of C language by Dennis M. Ritchie 和部分名称 Neonatal C 他写道:

[...] 在从 B 到 C 的转换中,人们想在这样的语句中将 & 替换为 &&;为了使转换不那么痛苦,我们决定保持 & 运算符相对于 == 的优先级相同,并且只是将 && 的优先级与 & 稍微分开。今天,似乎最好将 & 和 == 的相对优先级,从而简化了一个常见的 C 成语:要测试一个掩码值与另一个值,必须写

if ((a&mask) == b) ...

内括号是必需的,但很容易忘记。

不用担心 - 您不是第一个也不是最后一个忘记 &amp; 和另一个运算符上下文中的大括号的人。

【讨论】:

  • 更高的优先级将使事物按预期关联。这个答案需要s/higher/lower/g
  • 我不明白 - 编辑的意义何在? #if mode1 != 0 扩展为 #if mode &amp; 2 != 0,这仍然是相同的代码。宏在定义时不会被评估,而是在所有替换之后被评估 - 没有区别。不过,如果你愿意,你可以#if (mode1) != 0#define mode1 (mode &amp; 2)(或两者兼有......)
  • 操作员!= 正在工作。我不明白你缩小的范围 - 正如解释的那样,mode &amp; 2 != 0is checking the first bit。您提供了相同的代码,只是使用了另一个宏 - 没有区别。如前所述,宏在定义时不评估。使用运算符优先级上下文研究 macro pitfalls
  • 我的错误。我的第一语言不是英语,我误解了你。抱歉,感谢您的出色回答。
猜你喜欢
  • 2011-01-21
  • 2015-11-11
  • 1970-01-01
  • 2014-08-11
  • 1970-01-01
  • 1970-01-01
  • 2011-06-14
  • 2023-03-05
相关资源
最近更新 更多