-1

I want to write a conditional define in C with controlled with the arguments.

Something like this:

#define RTL_REG(reg_name,inst)     \
    inst == 0 ? DUT_0_##reg_name : \
    inst == 1 ? DUT_1_##reg_name : \
    inst == 2 ? DUT_2_##reg_name : \
    inst == 3 ? DUT_3_##reg_name : \
    DUT_0_##reg_name

But the code isn't working the way I want. Essentially it is substituting the value of inst for the define.

What I a, looking for is:

RTL_REG(CLK_EN,0) -> *DUT_0_CLK_EN*

RTL_REG(CLK_EN,1) -> *DUT_1_CLK_EN*

What I am getting:

RTL_REG(CLK_EN,0) -> 0

Can you some C experts help me out here?

Note: Tried adding () as well at the beginning and ending of the definition, but then again, "(" comes in the define substitution!

klutt
  • 30,332
  • 17
  • 55
  • 95
Arjun Ashok
  • 21
  • 1
  • 1
  • Possible duplicate of [C/C++ Macro string concatenation](https://stackoverflow.com/questions/5256313/c-c-macro-string-concatenation) (see second answer) – Nick is tired Jul 07 '18 at 14:39
  • 2
    and *what is* `DUT_0_CLK_EN` then? – Antti Haapala -- Слава Україні Jul 07 '18 at 14:41
  • Taken in isolation, the macro definition in the question converts `RTL_REG(CLK_EN,0)` into `0 == 0 ? DUT_0_CLK_EN : 0 == 1 ? DUT_1_CLK_EN : 0 == 2 ? DUT_2_CLK_EN : 0 == 3 ? DUT_3_CLK_EN : DUT_0_CLK_EN` which is what you want. However, if `DUT_0_CLK_EN` is itself defined as an object-like macro, then you will get further changes. Also, coding safety guidelines for macros suggests you should use `((inst) == 0) ? …` in the macro definition, and probably a set of parentheses around the whole expansion. – Jonathan Leffler Jul 07 '18 at 15:03

2 Answers2

0

You could just do

#define RTL_REG(reg_name,inst) DUT_##inst##_##reg_name

## is used to concatenating two tokens. See this.

J...S
  • 5,079
  • 1
  • 20
  • 35
0

The preprocessor does not support conditional expressions (like ?:). Instead, use a separate function macro to join the components:

#define  JOIN4(a, b, c, d)    a##b##c##d
#define  RTL_REG(name, inst)  JOIN4(DUT_, inst, _, name)

With that, RTL_REG(CLK_EN, 0) expands to DUT_0_CLK_EN, and RTL_REG(CLK_EN, 1) expands to DUT_1_CLK_EN.

The function-like macro call means that the macro arguments are evaluated by the preprocessor before the concatenation. This means that if you add a definition like

#define  CLK_EN  CLOCK_ENABLE

then RTL_REG(CLK_EN, 2) expands to DUT_2_CLOCK_ENABLE. If you further add

#define  DUT_  WEIRDPREFIX_

then RTL_REG(CLK_EN, 3) expands to WEIRDPREFIX_3_CLOCK_ENABLE.


Let's say you cannot use the same prefix (DUT_0, DUT_1). No worries; you just need to add one layer of function-like macro calls, and redefine the prefixes:

#define  JOIN3_(a, b, c)      a ## b ## c
#define  JOIN3(a, b, c)       JOIN3_(a, b, c)
#define  RTL_REG(name, inst)  JOIN3(DUT_ ## inst, _, name)

Then, if you do say these additional definitions,

#define  DUT_0   FIRST
#define  DUT_1   SECOND
#define  CLK_EN  CLOCK_ENABLE

then RTL_REG(CLK_EN, 0) expands to FIRST_CLOCK_ENABLE, and RTL_REG(CLK_EN, 1) to SECOND_CLOCK_ENABLE. And, of course, if you do additional definitions like

#define  FIRST_CLOCK_ENABLE   foo(1)
#define  SECOND_CLOCK_EANBLE  bar(2)

then RTL_REG(CLK_EN, 0) indeed expands to foo(1), and RTL_REG(CLK_EN, 1) to bar(2).

You just need to be careful if the intermediate terms are already defined as macros, to not get too surprised. If you are using GCC, you can run gcc -dD -E source-or-header-file to obtain the preprocessed source that includes all macro definition statements.

Nominal Animal
  • 38,216
  • 5
  • 59
  • 86