检查C预处理器中的连接定义



使用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段:

所有以下划线、大写字母或另一个下划线开头的标识符始终保留用于任何用途。

最新更新