【问题标题】:How can I get the gcc preprocessor to check if an expression evaluates to a value or nothing?如何让 gcc 预处理器检查表达式的计算结果是否为值?
【发布时间】:2016-08-11 14:18:26
【问题描述】:

我正在使用 gcc(特别是 avr-gcc)。

所以这是我的难题:

假设我在某处定义了这些:

#define THING_0_A 0
#define THING_0_B 1
#define THING_1_A 0

然后在第二个文件中我有这个:

#define CONCAT_(A,B,C) A ## B ## C
#define CONCAT(A,B,C) CONCAT_(A,B,C)

#define ID 0

#define THING_N(A) CONCAT(THING_,ID,A)

有了这个,我现在有一个选择的表达式(仍在第二个文件中):

THING_N(_A) // evaluates to 0
THING_N(_B) // evaluates to 1
THING_N(_C) // evaluates to... nothing? Or undefined? Or THING_0_C?

现在,我要解决的是如何做到这一点(也在第二个文件中):

#ifdef THING_N(_A)
    // Do something knowing that THING_N(_A) is defined (in this case THING_0_A)
#endif

或者:

#if THING_N(_A)
    // Do something knowing that the value THING_N(_A) evaluates to is defined and not just "nothing"
#endif

当然,这些都不起作用,因为 #ifdef 不能将表达式作为参数(无论如何它都会以“#ifdef 0”结尾),并且 THING_N(_A) 在 #if 内的计算结果为 0。

换句话说,我正在寻找一种让预处理器进行评估的方法:

THING_N(_A) to true
THING_N(_B) to true
THING_N(_C) to false
THING_N(_D) to false
etc...

用于条件句。

【问题讨论】:

  • 听起来很典型的XY problem
  • 你说的很对,这听起来确实像一个 XY 问题(我很高兴你提到它,因为我以前没有听说过这个名字),但在这种情况下,上面提到的是我的X. 如果有人可以计算出 Y,那么也许我将来会将该 Y 应用于 X。 (即,我问这个是为了好玩、好奇和渴望更好地理解 c 预处理器的工作方式。)
  • 如果问题没有实际目的,您可以随时添加“language-lawyer”标签,这意味着您只是对语言机制感兴趣而不是试图解决现实世界问题。

标签: c gcc c-preprocessor language-lawyer


【解决方案1】:

试试这个:

#if (1-THING_N(_A)-1 != 2)

对于THING_N(_A) 的每个值,这将是true(值-2 除外)。仅当 THING_N(_A) 未定义或定义为空时,它将为 false

如果您的宏有可能扩展为 -2,您可以将第二个 12 修改为您选择的其他文字,以便基本思想成立。

【讨论】:

  • 我真的很喜欢这个主意。不幸的是,它似乎对我不起作用。当 THING_N(_A) 未定义时,您编写的表达式的计算结果为 true。我猜是因为它按预期计算为(1-THING_0_A-1 != 2) 而不是(1- -1 != 2)
  • 我刚刚发现 c99 标准说未定义的标识符被替换为 0(不是什么都没有),这将给出:1-THING_0_A -1 != 2 -> 1-0 -1 != 2 -> 0 != 2 -> @987654335 @ (真的)。所以这就解释了。
【解决方案2】:

您可以将值与已知值连接,并检查结果:

#define EMPTY_VAL_HELPER(VAL)  VAL ## 1
#define EMPTY_VAL(VAL)         EMPTY_VAL_HELPER(VAL)

现在你可以这样做了:

#if defined(FOO) && (EMPTY_VAL(FOO) == 1)
//FOO is defined, but empty
#endif

#if defined(FOO) && (EMPTY_VAL(FOO) != 1)
//FOO is defined, and not empty
#endif

【讨论】:

  • 如果我只想检查#ifdef THING_0_A 之类的东西,#ifdef 本身的条件就可以完美地工作,但这不是我的问题要问的。我真正好奇的是你有一个宏并且你想检查宏计算的东西是否被定义的情况。例如#ifdef THING_N(_A) 其中THING_N(_A) 计算结果为THING_0_A(已定义),#ifdef THING_N(_C) 其中THING_N(_C) 计算结果为THING_0_C(未定义)。
【解决方案3】:

所以,经过大量研究和实验,我得出结论,我的问题没有解决方案,原因其实很简单。

鉴于我在问题中的设置,这就是表达式的评估结果:

THING_N(_A) -> THING_0_A -> 0
THING_N(_B) -> THING_0_B -> 1
THING_N(_C) -> THING_0_C -> 0 (Not nothing, as I previously thought.)

我之前遗漏的一条信息是,根据 c99 标准,未定义的标识符将被转换为 0,而不是什么都没有,因此无法区分未定义的内容和定义为 0 的内容。

如果选择 c99 标准来使未定义的标识符评估为空,就像 #define FOO 使 FOO 评估为空一样,那么 atturri 的解决方案就会奏效。

哦,好吧。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-19
    • 1970-01-01
    • 2017-07-12
    • 1970-01-01
    • 2014-11-20
    • 2016-11-04
    • 1970-01-01
    相关资源
    最近更新 更多