1

This is how symbol concatenation is done in C.

#define conc(a,b) a ## b

eg:

conc(hello,World) will make the symbol helloWorld.

What I need to know is a bit different. Say there's a variable n that hold some integer. Now I need to create a symbol by concatenating another symbol with the value of n.

Eg:

n = 2
I need to define some function(...) so that function(symbol,n) will give symbol1 (not symboln) and when n = 3, function(symbol,n) will give symbol3 etc...

How can I define something like that?


This is what i really want to achieve. First, this is to be used to in AtmelStudio to program an atmega micro-controller. There are 4 USART modules there so are seperate set of registers, which change there names only by the number of the module.

For example, the four baud rate registers in four modules are UBRR0L, UBRR1L, UBRR2L, UBRR3L. (and there are several more, see below).

enter image description here

I need to write a function to initialize a given module by setting up values of the relevant registers. Since the register names vary only by the module number, if I can define some pre-processor directive as asked in this post, I can write a single function representing register names by some symbols, so the symbols will be bear relevant register names and the thing will go fine..

Eg:

If i can define conc(a,b) to do what I need, a simple function

void init(int no){
    conc(UBRR,no) = 0xF0;
}

Will be able to use to represent all the followings;

UBRR0 = 0xF0;
UBRR1 = 0xF0;
UBRR2 = 0xF0;
UBRR3 = 0xF0;

If this is not achievable, only thing I know is to re-write four separate functions. But hope there will be better alternatives..

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Anubis
  • 6,995
  • 14
  • 56
  • 87
  • have a look at this question I have posted a while ago http://stackoverflow.com/questions/10379691/creating-macro-using-line-for-different-variable-names Still this will only work for constants, not for variables. – Ivaylo Strandjev Jan 07 '13 at 12:17
  • Please give us more context on what you want to achieve. You mean a variable or another macro that you want to expand? – Jens Gustedt Jan 07 '13 at 12:33

4 Answers4

5

Preprocessor will operate on your code, BEFORE compilation & obviously much before run time. So no preprocessor directive can solve your purpose.

The closest match would be to use a switch case as below:

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.
}

& then operate on *ptr...

Also if your variable names are going to be sequential, why not have an array, with name as symbol & symbol0 changed to symbol[0] ?

EDIT: Saw the edit in the question now. You can have switch case as shown above, or create an array of pointers, which will hold UBRR0L, UBRR0L etc. & then use it with index. As much as I know, they are just registers & will be present at fixed addresses.

anishsane
  • 20,270
  • 5
  • 40
  • 73
4

You can't do it using the C preprocessor because the values of variables are determined at runtime. But you can use snprintf() to build strings based on numbers like that at runtime.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • Ok, i need to use this in `avrgcc` to program a micro-controller. So `snprintf()` won't help. I'll have to look for some other way. Thanks for the answer anyway.. – Anubis Jan 07 '13 at 12:38
  • Perhaps you could tell us why snprintf() can't be used? – John Zwinck Jan 07 '13 at 12:56
  • please see the updated post. I'm not much experienced. There may be better ways to do that. If so, just let me know. – Anubis Jan 07 '13 at 13:08
2

It appears to me that the registers (for example RXC0, RXC1, RXC2, etc.) are equidistant. If this assumption is true you can calculate the address of the following register (simply replace rint by the type of the register):

rint *
register_address(rint *first, rint *second, unsigned int n)
{
    size_t diff = second - first;

    return first + diff * n;
}

Your init() function would then look like that:

void
init(int no)
{
    *register_address(&UBRR0, &UBRR1, no) = 0xF0;
}

This function call can be simplified/hidden by a macro:

#define register_value(name, no) *register_address(&conc(name, 0), &conc(name, 1), no)

so you can write:

void
init(int no)
{
    register_value(UBRR, no) = 0xF0;
}

This code is untested and I'm not sure if it really works. If it works and you are going to use it, I would test the assumption by a static assert.

quinmars
  • 11,175
  • 8
  • 32
  • 41
0

The real trick is the following:

#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)

Now we can use it as:

SET_TIMER_NORMAL_MODE(TIMER_0)

which expands to:

 _SET_TIMER_NORMAL_MODE(0)

furthermore, this expands to:

TCCR0 &= ~(1 << WGM00)