c - 带有扩展宏和类型转换的 C 条件预处理器
问题描述
对于微控制器,我将宏用于 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
}
它也无法使用 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
但这涉及另一个变量[编辑:技术上是一个宏,但实际上是我必须跟踪的另一组字符]。
如果可能的话,我很想知道编译错误背后的原因和/或如何解决它。
解决方案
引用C11
,第§6.10.1p4章
在评估之前,预处理标记列表中将成为控制常量表达式的宏调用被替换(除了那些由定义的一元运算符修改的宏名称),就像在普通文本中一样。如果定义的标记是作为替换过程的结果生成的,或者使用定义的一元运算符与宏替换之前的两种指定形式之一不匹配,则行为未定义。由于宏扩展和定义的一元运算符的所有替换都执行完毕后,所有剩余的标识符(包括那些在词法上与关键字相同的标识符)都被替换为 pp-number 0,然后将每个预处理标记转换为一个标记。...
在您的代码中,您正在比较 -
#if ((double)1)==((double)1)
因为double
不是一个有效的令牌,它被替换为(0)
.
本质上你是在比较 -
#if ((0)1)==((0)1)
由于语法错误,这不是有效的常量表达式。
当我用我的编译器运行它时clang
,我得到
错误:令牌不是预处理器子表达式中的有效二元运算符
您提到的解决方案似乎是一个不错的解决方案。您不必担心“但它涉及另一个变量”,因为这些不是变量而是宏。宏是编译时实体,不会以任何方式(内存、寄存器压力甚至执行时间)给您的运行时间带来负担。
推荐阅读
- amazon-web-services - CodePipeline (AWS) 的 CodeBuild (AWS) 无法正常工作
- python - 为什么 ImageDataGenerator 永远迭代?
- json - 我有一个包含 379000 行的 JSON 文件,它在字符串对象中充满了双引号,我怎样才能删除所有这些?
- html - 如何删除我的部分顶部的额外间距
- python-3.x - 如何使用 svm 对数组进行分类?
- java - Akka:观看演员的网络开销
- selenium - 编写机器人框架测试用例以使用以下 Web 元素搜索搜索输入关键字?
- php - 如何将 PSR 日志文件更改为每天仅一个
- regex - 如何使用 Google 表格中的 IFS 和 AND 函数根据数字的小数位数创建条件?
- regex - RegEx 以匹配具有特定模式的电话号码