这是在 C 中完成符号连接的方式。
#define conc(a,b) a ## b
例如:
conc(hello,World)
会生成符号helloWorld
。
我需要知道的是有点不同。假设有一个变量n
,它包含一些整数。现在我需要通过将另一个符号与值 n
连接来创建符号。
例如:
n = 2
我需要定义一些function(...)
,以便function(symbol,n)
提供symbol1
(不是symboln
),当n = 3
时,function(symbol,n)
会提供symbol3
等等......
我该如何定义类似的内容?
这是我真正想要实现的目标。首先,这将用于AtmelStudio
编程atmega
微控制器。那里有4个USART
模块,因此是一组独立的寄存器,只根据模块的数量改变名称。
例如,四个模块中的四个波特率寄存器是UBRR0L
,UBRR1L
,UBRR2L
,UBRR3L
。 (还有几个,见下文)。
我需要编写一个函数来通过设置相关寄存器的值来初始化给定模块。由于寄存器名称仅因模块编号而异,如果我可以按照本文中的要求定义一些预处理器指令,我可以用一些符号编写一个表示寄存器名称的函数,因此符号将带有相关的寄存器名称和事情会好起来的。
例如:
如果我可以定义conc(a,b)
来做我需要的,一个简单的函数
void init(int no){
conc(UBRR,no) = 0xF0;
}
将能够用来代表以下所有内容;
UBRR0 = 0xF0;
UBRR1 = 0xF0;
UBRR2 = 0xF0;
UBRR3 = 0xF0;
如果这是不可能实现的,我唯一知道的就是重写四个独立的功能。但希望有更好的选择..
答案 0 :(得分:5)
预处理器将在编译之前对您的代码进行操作。显然在运行时间之前。所以没有预处理器指令可以解决你的目的。
最接近的匹配是使用如下的开关案例:
switch(n){
case 0: ptr=&symbol0; break;
case 1: ptr=&symbol1; break;
case 2: ptr=&symbol2; break;
case 3: ptr=&symbol3; break;
case 4: ptr=&symbol4; break;
case 5: ptr=&symbol5; break;
//etc... needs to be filled manually.
}
&安培;然后在*ptr
...
此外,如果您的变量名称将是顺序的,为什么不具有数组,名称为符号& symbol0
已更改为symbol[0]
?
编辑:
现在看到问题中的编辑。
您可以如上所示使用switch case,或者创建一个指针数组,这些指针将保留UBRR0L
,UBRR0L
等。&然后将它与索引一起使用。据我所知,它们只是寄存器和放大器。将出现在固定地址。
答案 1 :(得分:4)
您无法使用C预处理器执行此操作,因为变量的值是在运行时确定的。但您可以使用snprintf()
根据运行时的数字构建字符串。
答案 2 :(得分:2)
在我看来,寄存器(例如RXC0,RXC1,RXC2等)是等距的。如果这个假设为真,你可以计算下面寄存器的地址(只需用寄存器的类型替换rint
):
rint *
register_address(rint *first, rint *second, unsigned int n)
{
size_t diff = second - first;
return first + diff * n;
}
您的init()
功能将如下所示:
void
init(int no)
{
*register_address(&UBRR0, &UBRR1, no) = 0xF0;
}
这个函数调用可以通过宏简化/隐藏:
#define register_value(name, no) *register_address(&conc(name, 0), &conc(name, 1), no)
所以你可以写:
void
init(int no)
{
register_value(UBRR, no) = 0xF0;
}
此代码未经测试,我不确定它是否真的有效。如果它可以工作并且您将要使用它,我将通过静态断言来测试该假设。
答案 3 :(得分:0)
真正的窍门如下:
#define TIMER_0 0
#define TIMER_1 1
#define TIMER_2 2
#define _SET_TIMER_NORMAL_MODE(val) TCCR ## val &= ~(1 << WGM ## val ## 0)
#define SET_TIMER_NORMAL_MODE(instance) _SET_TIMER_NORMAL_MODE(instance)
现在我们可以将其用作:
SET_TIMER_NORMAL_MODE(TIMER_0)
扩展为:
_SET_TIMER_NORMAL_MODE(0)
此外,它扩展为:
TCCR0 &= ~(1 << WGM00)