Generate non-stringified text literal macro at build time

Viewed 95

Background

In a separate question of mine, I created a function-like-macro that allows me to concatenate a user-supplied text literal to create a macro name, i.e.:

/******************************************************************************
 * coconut.h
 ******************************************************************************/
#define COCONUT_FX_REGISTER (100)
#define COCONUT_BASE_REGISTER   (101)

/*******************************************************************************
 * pineapple.h
 ******************************************************************************/
#define PINEAPPLE_FX_REGISTER   (200)
#define PINEAPPLE_BASE_REGISTER (201)

/*******************************************************************************
 * test.c.
 ******************************************************************************/
#include <stdio.h>
#include "translation.h"
#include "coconut.h"
#include "pineapple.h"

int main(void) {

    int i = getTranslation(FX_REGISTER, COCONUT);
    printf("Translation:%d.\n", i);

    return 0;
}

/*******************************************************************************
 * translation.h
 ******************************************************************************/
#define getTranslation(x, y)  y ## _ ## x

Goal

I would like to extend this logic so that I can use a macro for a default value to pass to getTranslation, i.e.:

#define XFRM(x)         #x
#define XFRM2(x)        XFRM(x)
#define DEFAULT_PRODUCT     XFRM2(COCONUT)

int main(void) {

    int i = getTranslation(FX_REGISTER, DEFAULT_PRODUCT);
    printf("Translation:%d.\n", i);

    return 0;
}

Problem

However, I can't seem to get DEFAULT_PRODUCT to be converted to a non-string text literal.


Build Errors

main.c: In function ‘main’:
main.c:14:35: error: ‘DEFAULT_PRODUCT_FX_REGISTER’ undeclared (first use in this function)
  printf("%d\n", getTranslation(FX_REGISTER, DEFAULT_PRODUCT));
                                   ^
translation.h:33:25: note: in definition of macro ‘getTranslation’
 #define getTranslation(x, y) y ## _ ## x
                         ^
main.c:14:35: note: each undeclared identifier is reported only once for each function it appears in
  printf("%d\n", getTranslation(FX_REGISTER, DEFAULT_PRODUCT));
                                   ^
translation.h:33:25: note: in definition of macro ‘getTranslation’
 #define getTranslation(x, y) y ## _ ## x

Question

How can I create a DEFAULT_PRODUCT macro that resolves to a non-string text literal so that I can create a "default" value to use with getTranslation? This is using GCC set to C99 pedantic.

2 Answers

Sounds like an XY problem.

It seems that macro concatenations are processed simultaneous to macro literal expansions, so I'm afraid there's no way to create a DEFAULT_PRODUCT macro that gets expanded before getTranslation.

My proposal: Create another macro function getDefaultTranslation(x) and you'll easily achieve what you want.

// You may want to add appropriate comments
// so code reviewers know what this is doing.
#define getDefaultTranslation(x) COCONUT ## x

Regarding this question, macro expansion is done layer-by-layer, and at the same layer concatenation has a higher precedence , so adding another layer should work. See ringø's answer below.

You need to add an indirection in order to let the preprocessor expand the macros before doing the concatenation

#define CONCAT(a, b) a ## _ ## b

#define getTranslation(x, y)  CONCAT(x,y)

#define XFRM(x)         x
#define XFRM2(x)        XFRM(x)
#define DEFAULT_PRODUCT XFRM2(COCONUT)

Note that XFRM has its # removed (off x), otherwise the " gives an invalid preprocessing token.

This way you get

int i = FX_REGISTER_COCONUT;
Related