使用GETREG
函数通过连接定义访问寄存器
#define NUMBER 1 //changes
#define REG1 register.N1
#define REG2 register.N2
#define REG8 register.N8
#define GETREG_(N) REG ## N
#define GETREG(N) GETREG_(N)
有时NUMBER
的寄存器没有定义,所以我想确保宏在插入代码之前正确展开,所以我试图这样做:
#define NUMBER 5
#ifdef GETREG(NUMBER)
GETREG(NUMBER) = 0
#endif
然而,这似乎总是为真,编译器输出
警告:#ifdef指令的末尾有额外的标记
背景故事:
在我的项目中,我创建了与HAL接口的库,以抽象硬件级别。通常从一个项目到另一个项目,HAL中的代码基础保持完全相同,只是引脚的位置发生了变化。出于这个原因,我想使用宏扩展来访问引脚。以下宏为我解决引脚的模拟特性:
#define ANSEL_(Pin) _ANS ## Pin
#define ANSEL(...) ANSEL_(__VA_ARGS__)
,这样我可以打开或关闭模拟功能:
#define PIN_RX A0
ANSEL(PIN_RX)= 0;
和其他寄存器通过类似的宏。我现在面临的问题是,一些引脚例如没有模拟功能(例如引脚A5)。因此,我想测试库中的定义是否存在。我想这样做:
#ifdef ANSEL(PIN_RX)
ANSEL(PIN_RX)= 0;
#endif
然而,这种简单的方法不起作用。
单片机(PIC33)库:编辑:从制造商发货
#define ANSELA ANSELA
extern volatile unsigned int ANSELA __attribute__((__sfr__));
typedef struct tagANSELABITS {
unsigned ANSA0:1;
unsigned ANSA1:1;
unsigned ANSA2:1;
unsigned ANSA3:1;
unsigned ANSA4:1;
unsigned :4;
unsigned ANSA9:1;
} ANSELABITS;
extern volatile ANSELABITS ANSELAbits __attribute__((__sfr__));
/* ANSELA */
#define _ANSA0 ANSELAbits.ANSA0
#define _ANSA1 ANSELAbits.ANSA1
#define _ANSA2 ANSELAbits.ANSA2
#define _ANSA3 ANSELAbits.ANSA3
#define _ANSA4 ANSELAbits.ANSA4
#define _ANSA9 ANSELAbits.ANSA9
您对#ifdef
指令的行为有错误的期望。该指令相当于#if defined
,其中defined
是该上下文中的预处理操作符。尽管整个#if
指令的条件只在该行完全宏展开之后才计算,但defined
运算符操作下一个预处理令牌,该令牌必须具有标识符的形式,在宏展开之前:
在求值之前,将替换将成为控制常量表达式的预处理令牌列表中的宏调用(由
defined
一元操作符修改的宏名称除外)[…]
[C2011 6.10.1/4]
,
#ifdef GETREG(NUMBER)
测试GETREG
是否是一个已定义的宏,(NUMBER)
构成一个意外的额外标记序列。
defined
操作符不能满足您的目的。可以想象,有一种方法可以使用更通用的#if
指令来实现您的目标,但我目前没有看到它。相反,我倾向于建议让编译器为您发现这些错误,而不是期望预处理器来做。如果编译时间太迟,那么也许你需要寻找一个构建配置系统,如Autotools或CMake可以帮助你创建。
如果您准备使用两个#define
s而不是每个引脚一个,则可以或多或少地做您想做的事情:
#define HAS_ANS_A0 1
#define ANS_A0 ANSELAbits.ANSA0
#define HAS_ANS_A1 1
#define ANS_A1 ANSELAbits.ANSA1
#define HAS_ANS_A5 1
#define ANS_A5 ANSELAbits.ANSA5
#define HAS_ANSEL_(Pin) HAS_ANS_ ## Pin
#define HAS_ANSEL(...) HAS_ANSEL_(__VA_ARGS__)
#define ANSEL_(Pin) ANS_ ## Pin
#define ANSEL(...) ANSEL_(__VA_ARGS__)
#if HAS_ANSEL(PIN_RX)
ANSEL(PIN_RX)= 0;
#endif
这是有效的,因为在#if
中,一个未定义的标识符令牌(即,一个不是#define
d的标识符令牌)的值为0。这不是一个错误,甚至不是一个警告。
注意:我改变了_ANS
开头的符号,以符合& section;7.1.3(保留名称),第1段:
所有以下划线、大写字母或另一个下划线开头的标识符始终保留用于任何用途。