C令牌替换 - 在某些点阻止宏替换

时间:2014-01-16 05:07:43

标签: c token c-preprocessor

我正在尝试为我目前编程的微控制器制作一段更通用的代码。

我想要的是一个特定的宏,通过串联从其他令牌形成。问题是其中一个令牌被定义为特定的存储器地址(即寄存器),因此“垃圾”在中途被替换。以下代码段说明了问题:

#include <stdio.h>
#include <stdint.h>

// The actual final token that I want (because I want the value of 10)
#define I_DRINK_BEER    10

// This line is the problematic line!
// It us defined in the microcontroller-specific header
// If this line is not defined, it works perfectly as desired.
#define DRINK           (*(uint32_t*) (0x8000))

#define ACTION          DRINK

#define INDIRECT(who,action,what)       who ## action ## what
#define TOKEN_PASTE(who,action,what)    INDIRECT(who,action,what)
#define CONSUMPTION(who,what)           TOKEN_PASTE(who,ACTION,what)

int main(void)
{
    printf("Value = %d\n", CONSUMPTION(I_,_BEER));
    return 0;
}

如果注释掉“#define DRINK ...”行,程序将根据需要编译并执行:

damien@damien-desktop:~$ gcc -o test test_macro_expansion.c
damien@damien-desktop:~$ ./test
Value = 10

但是包含违规行代替了使预处理器抱怨的完整地址:

test_macro_expansion.c: In function ‘main’:
test_macro_expansion.c:21:1: error: pasting "I_" and "(" does not give a valid preprocessing token
test_macro_expansion.c:21:1: error: pasting ")" and "_BEER" does not give a valid preprocessing token
test_macro_expansion.c:21:28: error: expected ‘)’ before ‘_BEER’

有没有办法告诉预处理器不要再替换特定的令牌?


为什么?

在此之前看起来有点深奥,我有一个特定功能的计时器,分配给一个项目中的计时器/计数器“TCC0”和另一个项目中的“TCD1”。它恰好被定义为每个定时器的寄存器块的基地址。所以,我有我的配置标题:

#define PERIPHERAL_TIMER    TCC0

其中,在main中运行良好,因为可以很容易地引用计时器的寄存器,例如:

value = PERIPHERAL_TIMER.CCA;

在工具链的深处,定义了TCC0:

#define TCC0    (*(TC0_t *) 0x0800)  /* Timer/Counter C0 */

问题是我有其他定义的宏,其中有TCC0)作为我在其他地方需要的名称的一部分,例如:

// Note the TCC0 in the function argument!
EventSystem_SetEventSource(EVSYS_CHMUX_TCC0_OVF_gc);

因此,我想定义符号

// Conceptually what I want!
#define EVENT_SOURCE(timer)    EVSYS_CHMUX_ ## timer ## _OVF_gc

// The "PERIPHERAL_TIMER" gets expanded to the address, not the token that I want
#define PERIPHERAL_EVENT       EVENT_SOURCE(PERIPHERAL_TIMER)

我希望这能解清为什么我在问这个问题。

2 个答案:

答案 0 :(得分:0)

#define DRINK (*(uint32_t) (0x8000))
这一行有一个错误,就像UNDEFINED Symbol uint一样。

答案 1 :(得分:0)

嗯,解决这个问题的最简单,最简单的解决方法是:

// It was this...
// #define PERIPHERAL_TIMER    TCC0

// And is now this
#define PERIPHERAL_TIMER_SUFFIX    C0

因此可以很容易地定义宏:

// Conceptually what I want - modified, but be sure to use 
// indirect substitution as required.
#define EVENT_SOURCE(timer)    EVSYS_CHMUX_TC ## timer ## _OVF_gc

仍然可以定义PERIPHERAL_TIMER以进行直接寄存器访问:

// Don't forget, you'll need to use indirect substitution
#define PERIPHERAL_TIMER    TC ## PERIPHERAL_TIMER_SUFFIX

// Registers can still be access as:
value = PERIPHERAL_TIMER.CCA;

注意:本文中的间接替换是指this answer中的技术。