3

I am attempting to make a section of code a bit more generic for a microcontroller that I am currently programming for.

What I want is a specific macro, formed from other tokens via concatenation. The problem is that one of the tokens is defined as a specific memory address (i.e. a register) and thus "garbage" is substituted mid-way. The following snippet illustrates the problem:

#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;
}

If the line "#define DRINK ..." is commented out, the program compiles and executes as desired:

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

But the inclusion of the offending line substitutes the complete address that makes the pre-processor complain:

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’

Is there a way I can tell the pre-processor not to substitute a particular token any further?


Why??

Before this seems a little esoteric, I have a timer for some particular functionality that is assigned to timer/counter "TCC0" in one project and "TCD1" in another project. It happens to be defined in as the base address of the register block for each timer, respectively. So, I have in my config header:

#define PERIPHERAL_TIMER    TCC0

Which, works well in the main, because the registers of the timer can be referenced easily, for example:

value = PERIPHERAL_TIMER.CCA;

Deep in the toolchain, TCC0 is defined:

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

The problem is that I have other macros defined in that have the TCC0) as part of the the name that I need elsewhere, for example:

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

Hence, I would like to define the symbol

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

I hope this clears up why I am asking the question.

Damien
  • 785
  • 3
  • 8
  • 18
  • I believe you could make a macro-dance, something like: `#define OLD_DRINK DRINK`, `#undef DRINK`, `#define SOMETHING_THAT_HAS_DRINK ...`, `#define DRINK OLD_DRINK`, `#undef OLD_DRINK`. – jweyrich Jan 16 '14 at 06:20
  • There isn't a standard mechanism to prevent expansion of a currently defined macro, so any technique that might be devised is not going to be all that portable. My best guess is that you will need to define an alternative symbol for use in token pasting uses, so that you stay clear of the system-provided name. If you don't mind treading on thin ice, you might consider using `_TCC0_`, so your pasting would omit the the underscores at the ends of `EVSYS_CHMUX_` and `_OVF_gc`. That's thin ice because names starting with an underscore and a capital letter are reserved for the implementation. – Jonathan Leffler Jan 16 '14 at 06:36
  • Failing that, I'd use some systematic prefix, perhaps P_TCC0, to do the job. I don't see any alternative, but I could be suffering from myopia. – Jonathan Leffler Jan 16 '14 at 06:37
  • @jweyrich, that can not restore `DRINK` to its original value. Once you `#undef` it, its gone. So whatever you done is equal to `#undef DRINK`, nothing else. – Dipto Jan 16 '14 at 09:42
  • @Dipto: true! The original DRINK is gone :-( My bad! – jweyrich Jan 16 '14 at 17:42
  • Don't neglect the possibility of generating the C content with another program (e.g. Python/Perl/whatever) statically during the build process or otherwise, rather than doing it with the C preprocessor... avoids a lot of this ugliness. – Colin D Bennett Jan 19 '14 at 04:54

2 Answers2

0

#define DRINK (*(uint32_t) (0x8000)).
this line has an error which is as UNDEFINED Symbol uint .

Moha the almighty camel
  • 4,327
  • 4
  • 30
  • 53
Pushpendra
  • 1,492
  • 1
  • 17
  • 33
0

Well, the simplest, easiest workaround that solves this particular issue is:

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

// And is now this
#define PERIPHERAL_TIMER_SUFFIX    C0

So the macros can be easily defined:

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

And PERIPHERAL_TIMER can still be defined for direct register access:

// 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;

NOTE: Indirect substitution in this post refers to the technique in this answer.

Community
  • 1
  • 1
Damien
  • 785
  • 3
  • 8
  • 18
  • It doesn't solve the issue for the general case, but is a sufficient workaround for my problem. – Damien Jan 18 '14 at 23:57