Generate non-stringified text literal macro at build time - c

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.

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

How to fix the macro expansion problem in C

How to fix the macro expansion issue below ?
#define GET_VAL 3,2
#define ADD_VAL(val0, val1) ((val0) + (val1))
void foo()
{
int res = ADD_VAL(GET_VAL);
}
The macro is getting expanded as below and resulting in an error. I am using MSVC 2019
res = 3,2 + ;
I even tried using a helper macro as below, but still getting the same error.
#define GET_VAL 3,2
#define ADD_VAL1(val0, val1) (val0 + val1)
#define ADD_VAL(val) ADD_VAL1(val)
Expecting expansion:
ADD_VAL(GET_VAL); --> ADD_VAL(3, 2); --> 3 + 2
By default msvc doesn't use a standard confirming preprocessor implementation, make sure to enable it with /Zc:preprocessor
Macros fully expand their arguments in isolation before pasting them into the replacement text, but the resulting tokens aren't separated into a new argument list. They way to fix your behavior is to create an intermediate macro that expands the arguments, and passes the expanded arguments to your macro:
#define GET_VAL 1,2
#define ADD_VAL(...) ADD_VAL_(__VA_ARGS__)
#define ADD_VAL_(a,b) ((a)+(b))
ADD_VAL(GET_VAL) // should work now
Another option is to write a fx macro that evaluates arguments and applies a function to them:
#define FX(f,...) f(__VA_ARGS__)
#define ADD_VAL(a,b) ((a)+(b))
FX(ADD_VAL,GET_VAL) // should work now
C preprocessor can be abused in horrible ways
#define GET_VAL 3,2
// #define ADD_VAL(val0, val1) ((val0) + (val1))
#define ADD_VAL(val) ((int [2]){val}[0] + (int [2]){val}[1])
int main() {
printf("%d\n",ADD_VAL(GET_VAL));
}
Output
5

C Preprocessor: concatenate macro call with token

I'm trying to concatenate a macro call with a token to create a new one, for instance:
#define TEST(X) X ## _TEST
#define CONCAT(X) TEST(X) ## _CONCAT
CONCAT(OK);
Then I check the output with gcc -E; I would want to get OK_TEST_CONCAT; but instead I get an error:
error: pasting ")" and "_CONCAT" does not give a valid preprocessing token
If I remove ## I get no error but the output is OK_TEST _CONCAT;
This is a minimal example, so the easiest here would be to combine everything in a single macro, but know that it's impossible for me to get rid of the first call to TEST. Is there a way to remove that space?
Thanks
EDIT:
Ok so from the confusion maybe my example was a little too minimal, that's my fault. Here is a more plausible use case:
I want all the prototypes in a certain header to be prefixed by the PREFIX defined in that header.
proto.h:
#define EXPAND(X) EXPAND_HELPER(X)
#define EXPAND_HELPER(X) X
#define PROTO(NAME) PREFIX ## NAME
other.h:
#include <proto.h>
#define PREFIX other
int PROTO(test)(int a, int b);
...
What I want is all the prototypes in other.h to have this form: int other_test(int a, int b);. But as it is they have this form: int PREFIX_test(int a, int b);. After googling I found that I needed to force PREFIX to rescan, so I tried this:
#define PROTO(NAME) EXPAND(PREFIX) ## NAME
which prompted my question. Now if I look at #Lundin's answer, I can adapt it to give what I want:
Solution:
#define PROTO(NAME) PROTO_HELPER(PREFIX, NAME)
#define PROTO_HELPER(PREFIX, NAME) PROTO_EXPAND(PREFIX, NAME)
#define PROTO_EXPAND(PREFIX, NAME) PREFIX ## NAME
Thanks!
All preprocessor tokens must be expanded before a function-like macro using ## or # is called. Because ## or # is applied before macro expansion. In your case TEST(X) only expands X into TEST(OK) and then the preprocessor attempts to paste TEST(OK) with _CONCAT which won't work. For each attempt to concatenate tokens, you must first expand all macros before ##, which is done by extra helper macros that force a rescanning/replacement.
The contrived solution given #define TEST(X) X ## _TEST would be this:
#define CONCAT(X) EXPAND_HELPER(TEST(X)) // expands TEST(X) to TEST(OK)
-->
#define EXPAND_HELPER(X) CONCAT_HELPER(X, _CONCAT) // expands TEST(OK) to OK_TEST
-->
#define CONCAT_HELPER(X,Y) X ## Y
That is:
// NOTE: contrived solution, avoid
#define TEST(X) X ## _TEST
#define CONCAT_HELPER(X,Y) X ## Y
#define EXPAND_HELPER(X) CONCAT_HELPER(X, _CONCAT)
#define CONCAT(X) EXPAND_HELPER(TEST(X))
...
int CONCAT(OK) = 1; // becomes int OK_TEST_CONCAT = 1;
A much simpler solution would be:
#define CONCAT(X) X ## _TEST ## _CONCAT

Macro-function to generate macro with prefix (avoid stringification)

Background
I have a project where I have two separate products with near-identical macro names, for which I would like to create a macro-like-function to retrieve the values of the macros quickly. I have written a getTranslation macro-function to take the literal text provided to the "function", which should be treated as a string and a string prefix (shown below).
Question
How can I accomplish this operation of taking the arguments supplied to the macro, concatenating them together (with an underscore in the middle), and treating that result as a preprocessor macro instead of a string?
Code Listing
/*******************************************************************************
* coconut.h
******************************************************************************/
#define COCONUT (PRODUCT_COCONUT)
#define COCONUT_FX_REGISTER (100)
#define COCONUT_BASE_REGISTER (101)
/*******************************************************************************
* pineapple.h
******************************************************************************/
#define PINEAPPLE (PRODUCT_PINEAPPLE)
#define PINEAPPLE_FX_REGISTER (200)
#define PINEAPPLE_BASE_REGISTER (201)
/*******************************************************************************
* test.c.
******************************************************************************/
#include <stdio.h>
#include "translation.h"
#include "coconut.h"
int main(void) {
int i = getTranslation(FX_REGISTER, COCONUT);
printf("Translation:%d.\n", i);
return 0;
}
/*******************************************************************************
* translation.h
******************************************************************************/
#define FX_REGISTER (0)
#define BASE_REGISTER (1)
#define getTranslationInternal(x, y) #y "_" #x
#define getTranslation(x, y) getTranslationInternal(x, y)
enum Products {
PRODUCT_COCONUT = 0,
PRODUCT_PINEAPPLE,
PRODUCT_MAX,
PRODUCT_INVALID = (-1)
};
Compiler Warnings
test.c: In function ‘main’:
test.c:10:45: warning: initialization makes integer from pointer without a cast [-Wint-conversion]
int i = getTranslation(FX_REGISTER, COCONUT);
^
translation.h:7:39: note: in definition of macro ‘getTranslationInternal’
#define getTranslationInternal(x, y) #y "_" #x
^
test.c:10:10: note: in expansion of macro ‘getTranslation’
int i = getTranslation(FX_REGISTER, COCONUT);
Sample Run
Translation:4195812.
#define getTranslationInternal(x, y) y ## _ ## x
worked for me on clang, if you drop parentheses around the macro definitions.

Macro concatenation inside other macro concatenation in c

I have the following macros:
#define __IR( x ) ICU.IR[ IR ## x ].BIT.IR
#define _IR( x ) __IR( x )
#define IR( x , y ) _IR( _ ## x ## _ ## y )
I use it in this way:
IR(SCI7, RXI7) = 0;
That expands to:
ICU.IR[ IR_SCI7_RXI7 ].BIT.IR = 0
Instead of use SCI7 and RXI7 I'd like to use sci(channel) and rxi(channel). So I've tried to create the following macros:
#define _sci(x) SCI ## x
#define sci(x) _sci(x)
#define _rxi(x) RXI ## x
#define rxi(x) _rxi(x)
#define channel 7
And then:
IR(sci(channel), rxi(channel)) = 0;
But it didn't work. The compiler returns me:
Error[Pe017]: expected a "]"
I've been trying to with other manners also but without success.
What I'm doing wrong?
The whole macro is expanded with the literal sub-epressions and the macros in the result expression are expanded after that.
So you could write:
#define __IR(x ) ICU.IR[ IR ## x ].BIT.IR
#define _IR(x, y) __IR(_ ## x ## _ ## y)
#define IR(x, y) _IR(x, y)
#define _sci(x) SCI ## x
#define sci(x) _sci(x)
#define _rxi(x) RXI ## x
#define rxi(x) _rxi(x)
#define channel 7
IR(sci(channel), rxi(channel)) = 0;
(The only thing I've really changed is the definition of _IR. On anther note, macro identifiers and symbold beginning with underscores are reserved for the compiler, so you might want to rename your secondary macros.)
You're making the mistake of believing a macro function is like a function call whereas it actually involves text substitution on source code.
In rough terms, the preprocessor will expand IR(sci(channel), rxi(channel)) = 0 to _IR( _sci(channel)_rxi(channel)) = 0 and expands that to ICU.IR[IR_sci(channel)_rxi(channel)].BIT.IR = 0. The result of all that is then compiled as C.
That bit between the square brackets is not a valid C expression at all. The compiler gets confused on that, hence the cryptic error message.
That's the explanation for the problem. The solution? You haven't given enough information to help anyone suggest one.

C Macro building with defines

I am having trouble getting this macro expanison right
#define foo Hello
#ifdef foo
#define wrapper(x) foo ## x
#else
#define wrapper(x) boo ## x
#endif
calling:
wrapper(_world)
I would like the result of
Hello_world
however, the macro is treating the "foo" define as a literal, and thus giving
foo_world
Can someone point out my mistake?
Thanks
I would recommend gnu-cpp-manual which clearly explains how macros are expanded.
Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they(macro arguments) are stringified or pasted with other tokens (by the macro function that is directly applied to).
For example:
If an argument is stringified or concatenated, the prescan does not occur.
#define AFTERX(x) X_ ## x
#define XAFTERX(x) AFTERX(x)
#define TABLESIZE 1024
#define BUFSIZE TABLESIZE
AFTERX(BUFSIZE) => X_BUFSIZE: since AFTERX is to concatenate argument with prefix, its argument is not expanded, remaining BUFSIZE.
XAFTERX(BUFSIZE) => X_1024: XAFTERX does not do concatenation directly, so BUFSIZE will be expanded first.
Generally, arguments are scanned twice to expand macro called in them.
--- edit ---
So the better practice is: (code from QEMU source)
#ifndef glue
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#define stringify(s) tostring(s)
#define tostring(s) #s
#endif
glue(x,y) will concatenate x and y with both already expanded.

Resources