【问题标题】:C Preprocessor conditional with extended macros and typecast [closed]具有扩展宏和类型转换的 C 预处理器条件 [关闭]
【发布时间】:2018-05-18 10:18:31
【问题描述】:

对于微控制器,我将宏用于 HAL。现在,为了概括 HAL 的使用,我想做类似的事情

#define UART  UART1
#if UART==UART1
# define PIN_TX 9
#elif UART==UART2
# define PIN_TX 2
#else
# warning "UART not correctly defined"
#endif

但是,UART1 是具有类型转换的内存地址(例如 (uint8_t*)0x004000000)。所以编译器会打印一些错误。

我做了一个简单的例子:

#include <stdio.h>

#define v1 (double)1
#define v2 (double)2

int main(int argc, char *argv[])
{
  printf("We have: ");

#define VAL (v1)

#if VAL==v1
  printf("VAL is 1\n");
#elif VAL==v2
  printf("VAL is 2\n");
#else
# warning "VAL not 1 or 2"
  printf("Not defined\n");
#endif
}

以下 cmets 也无法使用 gcc 编译:

cc     preproc.c   -o preproc
preproc.c: In function ‘main’:
preproc.c:3:20: error: missing binary operator before token "1"
 #define v1 (double)1
                    ^
preproc.c:10:14: note: in expansion of macro ‘v1’
 #define VAL (v1)
              ^~
preproc.c:12:5: note: in expansion of macro ‘VAL’
 #if VAL==v1
     ^~~
preproc.c:3:20: error: missing binary operator before token "1"
 #define v1 (double)1
                    ^
preproc.c:10:14: note: in expansion of macro ‘v1’
 #define VAL (v1)
              ^~
preproc.c:14:7: note: in expansion of macro ‘VAL’
 #elif VAL==v2
       ^~~
preproc.c:17:2: warning: #warning "VAL not 1 or 2" [-Wcpp]
 #warning "VAL not 1 or 2"
  ^~~~~~~
<builtin>: recipe for target 'preproc' failed
make: *** [preproc] Error 1

但是,如果我删除 v1 和 v2 定义中的 (double),它会按预期编译和运行。


请注意,作为我提出的替代解决方案

#define USE_UART1
//#define USE_UART2

#if defined(USE_UART1)
# define UART UART1
# define PIN_TX 9
#elif defined(USE_UART2)
# define UART UART2
# define PIN_TX 2
#else
# warning "UART not correctly defined"
#endif

但这涉及另一个变量[编辑:技术上是一个宏,但实际上是我必须跟踪的另一组字符]。

我很想知道编译错误背后的原因和/或如果可能的话如何解决它。

【问题讨论】:

  • 你的问题不清楚。你在寻找什么理由?您是否正在寻找为什么需要使用辅助标识符作为键的理由?那是因为预处理器是有限的。您是否正在寻找预处理器受限的原因?这是因为它是一个历史产物,旨在帮助构建和自定义源代码,而不是完全集成的语言的一部分。
  • 我不知道您的最终解决方案有什么困扰。这对我来说似乎很合法。
  • 您的直接问题是double 转换无法被评估#if预处理器 解释。除此之外,我不知道你在问什么。
  • @EricPostpischil,我想了解它为什么不起作用。所以说理。如果可能的话,一种使其按预期工作的方法,但 Ajay 的回答似乎放弃了这种可能性。
  • @малинчекуров 它可以完成这项工作,但我觉得它不太优雅。我猜是味道和一切。

标签: c c-preprocessor preprocessor


【解决方案1】:

引用C11,章节§6.10.1p4

在评估之前,预处理标记列表中将成为控制常量表达式的宏调用被替换(除了那些由定义的一元运算符修改的宏名称),就像在普通文本中一样。如果定义的标记是作为替换过程的结果生成的,或者使用定义的一元运算符与宏替换之前的两种指定形式之一不匹配,则行为未定义。 由于宏扩展和定义的一元运算符的所有替换都执行完毕后,所有剩余的标识符(包括词法上与关键字相同的标识符)都替换为pp-number 0,然后转换每个预处理标记成令牌。 ...

在您正在比较的代码中 -

#if ((double)1)==((double)1)

由于double 不是有效令牌,它被(0) 替换。

本质上你是在比较 -

#if ((0)1)==((0)1)

由于语法错误,这不是一个有效的常量表达式。

当我用我的编译器clang 运行它时,我得到了

错误:标记在预处理器子表达式中不是有效的二元运算符

您提到的解决方案似乎是一个不错的解决方案。您不应该担心“但它涉及另一个变量”,因为这些不是变量而是宏。宏是编译时实体,不会以任何方式(内存、寄存器压力甚至执行时间)给您的运行时间带来负担。

【讨论】:

    【解决方案2】:

    与您的可行替代方案类似的方法是解决此类问题的常用方法。另一种是有某种配置程序,将适当的宏定义写入头文件。

    但这涉及另一个变量 [...]

    不,根本不涉及任何变量。预处理器宏不是变量,它们是。除了少数表面上的方式外,它们的行为不像变量。假设否则就是导致你走上错误道路的原因。宏代表源代码块,而变量代表运行程序中的存储位置。

    【讨论】:

      猜你喜欢
      • 2020-09-18
      • 2018-01-04
      • 2020-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多