Search code examples
cmacrosc-preprocessoravr-gcc

Pre-processor directive to concatenate a symbol with a variable value in C


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


Solution

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