具有扩展宏和类型转换的 C 预处理器条件
C Preprocessor conditional with extended macros and typecast
对于微控制器,我为 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 是一个带有类型转换的内存地址(e.x。(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
}
使用 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
但这涉及另一个变量[编辑:技术上是一个宏,但实际上是我必须跟踪的另一组字符]。
我很想知道编译错误背后的基本原理and/or如何解决它,如果可能的话。
引用 C11
,章节 §6.10.1p4
Prior to evaluation, macro invocations in the list of preprocessing tokens that will become the controlling constant expression are replaced (except for those macro names modified by the defined unary operator), just as in normal text. If the token defined is generated as a result of this replacement process or use of the defined unary operator does not match one of the two specified forms prior to macro replacement, the behavior is undefined. After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers (including those lexically identical to keywords) are replaced with the pp-number 0, and then each preprocessing token is converted into a token. ...
在您的代码中,您正在比较 -
#if ((double)1)==((double)1)
因为 double
不是有效的标记,它被替换为 (0)
。
本质上你是在比较 -
#if ((0)1)==((0)1)
由于语法错误,这不是有效的常量表达式。
当我 运行 使用我的编译器 clang
时,我得到
error: token is not a valid binary operator in a preprocessor subexpression
您提到的解决方案似乎是一个不错的解决方案。你不应该担心 "But it involves another variable" 因为这些不是变量而是宏。宏是编译时实体,不会以任何方式增加您的 运行 时间(内存、寄存器压力甚至执行时间)。
与您的工作替代方案类似的东西是解决此类问题的常用方法。另一种方法是使用某种配置程序,将适当的宏定义写入头文件。
But that involves another variable [...]
不,根本不涉及变数。预处理器宏不是变量,它们是宏。它们的行为不像变量,除了少数表面的方式。否则就是导致您走上错误道路的原因。宏代表源代码块,而变量代表 运行 程序中的存储位置。
对于微控制器,我为 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 是一个带有类型转换的内存地址(e.x。(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
}
使用 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
但这涉及另一个变量[编辑:技术上是一个宏,但实际上是我必须跟踪的另一组字符]。
我很想知道编译错误背后的基本原理and/or如何解决它,如果可能的话。
引用 C11
,章节 §6.10.1p4
Prior to evaluation, macro invocations in the list of preprocessing tokens that will become the controlling constant expression are replaced (except for those macro names modified by the defined unary operator), just as in normal text. If the token defined is generated as a result of this replacement process or use of the defined unary operator does not match one of the two specified forms prior to macro replacement, the behavior is undefined. After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers (including those lexically identical to keywords) are replaced with the pp-number 0, and then each preprocessing token is converted into a token. ...
在您的代码中,您正在比较 -
#if ((double)1)==((double)1)
因为 double
不是有效的标记,它被替换为 (0)
。
本质上你是在比较 -
#if ((0)1)==((0)1)
由于语法错误,这不是有效的常量表达式。
当我 运行 使用我的编译器 clang
时,我得到
error: token is not a valid binary operator in a preprocessor subexpression
您提到的解决方案似乎是一个不错的解决方案。你不应该担心 "But it involves another variable" 因为这些不是变量而是宏。宏是编译时实体,不会以任何方式增加您的 运行 时间(内存、寄存器压力甚至执行时间)。
与您的工作替代方案类似的东西是解决此类问题的常用方法。另一种方法是使用某种配置程序,将适当的宏定义写入头文件。
But that involves another variable [...]
不,根本不涉及变数。预处理器宏不是变量,它们是宏。它们的行为不像变量,除了少数表面的方式。否则就是导致您走上错误道路的原因。宏代表源代码块,而变量代表 运行 程序中的存储位置。