C macro expansion including compiler switches - c

My current implementation defines a couple of variables depending on corresponding compiler switches:
#ifdef ENABLE_var1
int var1;
#endif
#ifdef ENABLE_var2
int var2;
#endif
The compiler switches will be set by -D option during make. The names will always consist of the same prefix and the variable name. Since it is always the same strategy, my idea is to replace this using a macro like:
DECLARE(var1)
DECLARE(var2)
Calling make -DENABLE_var1 should result in:
int var1;
Calling make -DENABLE_var1 -DENABLE_var2 should result in:
int var1;
int var2;
Since it is not possible to use #ifdef within a macro, is there a trick to achieve this?

As long as the variable names to be defined, potentially, are known, then this can be accomplished:
// Define a DEFINE_x macro for each x that might be enabled.
#if defined ENABLE_var1
#define DEFINE_var1 int var1;
#else
#define DEFINE_var1
#endif
#if defined ENABLE_var2
#define DEFINE_var2 int var2;
#else
#define DEFINE_var2
#endif
// Define DECLARE(x) to expand to the corresponding DEFINE_x macro.
#define DECLARE(x) DEFINE_##x
// List potential definitions.
DECLARE(var1)
DECLARE(var2)
If the names are not known, then this kludge works:
#define Comma() ,
#define Argument3c(a, b, c,...) c
#define Argument3b(a, b,...) Argument3c(a, b, __VA_ARGS__)
#define Argument3a(a,...) Argument3b(a, __VA_ARGS__)
#define Nullify1
#define NullifyHelper(x) Nullify##x
#define Nullify(x) NullifyHelper(x)
#define DECLARE(x) Argument3a(Comma Nullify(ENABLE_##x) (), int x;,,)
DECLARE(var1)
DECLARE(var2)
Understanding this requires following the preprocessing in great detail, but I will provide a few notes:
For -Dname, GCC defines name to be replaced by 1. The Nullify macro, with its helpers, causes ENABLE_x to be replaced by an empty sequence if ENABLE_x is defined to be 1 and by a non-empty sequence otherwise.
Then, if an empty sequence has resulted, we have Comma (), which expands to a comma. If it is not an empty sequence, we have Comma something (), which does not allow the function-like macro to be expanded, so some sequence not including a comma results.
Through the remaining macro expansions, this comma or lack thereof determines which argument is where in the argument list, allowing us to pick out either the desired definition or an empty sequence.
I advise against using this in production code. There is likely a better way to accomplish your configuration goal.

Related

How to force macro to not expand

Using the following code:
#include <stdio.h>
typedef struct
{
int APB1ENR;
int b;
int c;
} RCC_TypeDef;
typedef struct
{
int a;
int b;
int c;
} USART_TypeDef;
#define USART2_BASE 0x1000
#define USART2 ((USART_TypeDef *) USART2_BASE)
#define RCC_BASE 0x2000
#define RCC_APB1ENR_USART2EN_Pos (17U)
#define RCC_APB1ENR_USART2EN_Msk (0x1UL << RCC_APB1ENR_USART2EN_Pos)
#define RCC_APB1ENR_USART2EN RCC_APB1ENR_USART2EN_Msk
#define RCC ((RCC_Typedef *) RCC_BASE)
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define __HAL_RCC_USART2_CLK_ENABLE() SET_BIT(RCC->APB1ENR, (RCC_APB1ENR_USART2EN))
#define UART_PERIPH USART2
#define CONCATENATE(x) // What comes here??
int main()
{
CONCATENATE(UART_PERIPH);
// | should expand to __HAL_RCC_USART2_CLK_ENABLE();
}
How can we define CONCATENATE(x) macro to expand only one layer deep. Using two levels of indirection it would expand all the way to pointer to structure, what I want is to expand UART_PERIPH only one layer and paste it together to form an already existing macro from its argument.
Is this possible?
How can we define CONCATENATE(x) macro to expand only one layer deep. ... Is this possible?
No. Here's what you have available. When macro invocation occurs, the first step is argument substitution (a.s.; 6.10.3.1); during that step, the tokens in the argument are evaluated if their corresponding parameter is mentioned in the macro's replacement list with said mention not being involved in a stringification or paste. The resulting expansion is substituted for said parameters in the replacement list. Next, stringification/pastes are applied in no particular order. Finally, rescan and further replacement (r.a.f.r; 6.10.3.4p1) occurs, during which the resulting replacement list itself is scanned; during this scan, the macro's name is "painted blue" (6.10.3.4p2; "blue paint" is not mentioned by name but is technical jargon for this), meaning if it's encountered it will not expand further.
So let's look at it from this point of view. UART_PERIPH is an identifier. Either it will be recognized as a macro in some context (i.e., will trigger macro invocation), or it will not. It doesn't matter if the context is during an a.s. or a r.a.f.r.; if this is invoked, the invocation involves r.a.f.r. (no a.s. because it's object-like). So the invocation involves taking USART2 and rescanning it. The only possible way for this to not expand USART2 is for this identifier to not be recognized as a macro, but since it's currently defined as one, the only way for that to happen is for this identifier to be painted blue. That's not possible (at least in the intended context) because USART2 would have to be expanding for this to happen, and by that time you're already injecting tokens you don't want.

Function-style macro with no-op if a condition is false

Suppose I have the following construct in multiple places in my code and want to make my code more legible:
#if HAVE_LIBFOOBAR
foobar_func(data);
#endif
I was thinking of writing a function-style macro around this, which would handle the conditionals, making the occurrences in the code look like a regular function call:
foobar_func_if_available(data)
If the condition is true, this would be replaced with a call to the actual function, else it would be a no-op.
Thus, something like:
#if HAVE_LIBFOOBAR
#define foobar_func_if_available(x) foobar_func(x)
#else
#define foobar_func_if_available(x) {}
#endif
Questions:
Does {} work as a no-op? Is it safe from having unintended effects (such as being used in an unbracketed if statement)? If not, what would I use?
Do I have to have two independent #defines wrapped in conditionals, or is there a way to do it the other way round (one #define with the conditionals inside the function-style macro)?
Edit: it has been suggested that this is a duplicate of another question, but in my opinion it is not: the other question asks “what is the problem solved with this construct”, mine is “what construct will solve my problem”. Indeed the other question has a possible solution to my problem, it does not cover all aspects of my question.
Create a dummy function and make the #define point at it (conditionally):
#if HAVE_LIBFOOBAR
#define foobar_func_if_available(x) foobar_func(x)
#else
int dummy(int ignored)
{
return 0;
}
#define foobar_func_if_available(x) dummy(x)
#endif
Or just :
#define foobar_func_if_available(x) 0
You cannot achieve it with a single #define.
You do not need {} as a no-op, you can define an empty expression in a number of ways:
#define foobar_func_if_available(x)
#define foobar_func_if_available(x) ;
#define foobar_func_if_available(x) do{}while(0)
There are circumstances where either of these may cause syntactic issues, but for void functions neither is likely to cause a problem - the solution breaks down for non-void functions however.
A better solution avoiding function-like macros altogether is to define the function body conditionally:
void foobar_func( int n )
{
#if defined HAVE_LIBFOOBAR
// do something
#else
// do nothing
#endif
}
whether the empty function results in no code is a matter for the compiler and the optimisation level applied, but importantly the code will work syntactically in all situations where a call to foobar_func() is valid. To worry about it being a no-op or not is probably sweating the small stuff.
Macros like ((int)0) or ((void)0) are probably the most flexible/safest no-op macros. They're flexible because you can use them
in expressions (unlike do{}while(0)) and they don't break if-else like {} or ; would.
Example of how {} (or ;) macros break if-else:
#define foo() {}
if(1) foo(); else bar(); //syntax error because if(1) {}; else bar(); was pasted
If the macro should emulate an integer returning function, it's better to use a casted integer literal over a plain integer constant as integer constants (and especially zeros) are usable in more contexts (case labels, bitfield sizes, array sizes , null pointer constants) than non-const integer expressions.
You don't need to have two macros as in:
#if HAVE_LIBFOOBAR
#define foobar_func_if_available(x) foobar_func(x)
#else
#define foobar_func_if_available(x) ((void)0) /*if foobar_func returns void*/
#endif
You can put the condition inside the macro:
#define foobar_func_if_available(x) \
(HAVE_LIBFOOBAR?foobar_func(x):((void)0))
Even a very dumb compiler should be able to optimize the constant conditional out.
But if you rely on an empty HAVE_LIBFOOBAR evaluating to 0 inside an #if, then the above won't work -- HAVE_LIBFOOBAR will need to be an integer.
(
You could do
#if !HAVE_LIBFOOBAR
#undef HAVE_LIBFOOBAR
#define HAVE_LIBFOOBAR 0
#endif
#define foobar_func_if_available(x) \
(HAVE_LIBFOOBAR?foobar_func(x):((void)0))
to normalize an empty HAVE_LIBFOOBAR into 0 but unless you will reuse the now assured HAVE_LIBFOOBAR's definedness, it seems like an unnecessary complication over the original two foobar_func_if_available macros.
)

Distinguish variable and constant in #define macro

I have macros like this:
#define _DDR_0 DDRD
#define _DDR_1 DDRD
#define _DDR_2 DDRD
// ....
#define _PN_0 0
#define _PN_1 1
#define _PN_2 2
// ...
/** Configure pin as output */
#define as_output(pin) sbi(_DDR_##pin, _PN_##pin)
void as_output_n(const uint8_t pin);
It is used like so:
as_output(2);
uint8_t b = 1;
as_output_n(b);
The _n variant is used for variables, the macro for constants (because it's much faster to do this with a macro).
Is there any possible way to make it so you can use as_output always, and depending on it being constant OR a variable, use the macro OR the function?
Macros are expanded by the preprocessor which has no knowledge of what the code does. From the preprocessor's point of view all the macro arguments are simply tokens (with no logical meaning). In this case as_output macro is used to manufacture new code (via token pasting).
So, what you're trying to do, is not possible using just macros (there could be a way if b would be a macro itself, but i guess that's not what you're looking for).
You could use a const array for your _DDR* and PN* values, and an inline function instead of macros.

Double slash comment substituition within a macro

I am developing a PIC MCU program on an ansi-compliant compiler (Microchip XC8).
There are two operation modes, determined via macros during compilation time.
So that I don't want to duplicate one function-like macro due to one line of code, I would like to know if there is any way to write a macro such as
#define FOO //
so that when FOO is substituted it will actually cancel the rest of the line.
Writing a function instead of a macro is out of the question because the delay generated by function calls would disrupt the tight timings of my program (around some microseconds).
You can't make a macro expand to comment out the line, no. // in a macro definition is a comment following the definition, it's not expanded, and IIRC there's a rule saying that you cannot construct a // using token-pasting. Even if you can, expanding it doesn't mean that the macro starts a comment. Basically, you don't get to change the comment syntax using macros.
You could do:
#if DO_NOTHING_MODE
#define FOO(ARG1)
#else
#define FOO(ARG1) ARG1
#endif
and use it like:
#define FUNCTION_LIKE_MACRO(ARG1, ARG2) \
required line; \
FOO(optional line;) \
Although a more common idiom is to design the macro to accept an expression as its argument, rather than a whole line:
#if DO_NOTHING_MODE
#define FOO(ARG1) ((void)0)
#else
#define FOO(ARG1) (ARG1)
#endif
and use it like FOO(optional line);
Either way, if the macro argument has commas in it, then the caller needs to enclose them in parentheses FOO((1,2)), although in C99 you can avoid that by making FOO a variadic macro:
#define FOO(...) (__VA_ARGS__)
You can use the #ifndef directive to achieve the same effect:
#ifndef FOO
your_line_of_code
#endif
EDIT: #SteveJessop made me see I didn't pay attention to this sentence of the OP "I don't want to duplicate one function-like macro due to one line of code". Here is what could be done in that case, if duplicating the function-like macro is not wanted:
// When FOO is defined, BLA in FUNC macro is a no-operation (null statement)
#ifndef FOO
#define BLA() a++
#else
#define BLA()
#endif
#define FUNC() \
BLA(); \
b++;
Comments are removed from the source before macro replacement occurs, so there's no way to define a macro exactly like that. However, it is certainly possible to pass an additional parameter into the macro to specify which code it should generate, or conditionally define the macro depending on the mode for which you are compiling.
#define FOO(...) __VA_ARGS__
And then use FOO(your code here) instead of FOO your code here in the macro.
If your platform doesn't have C99, you can instead use
#define FOO(x) x
and just make sure the argument doesn't contain a , not enclosed in ().

How to define a define in C?

Is it possible to write a #define that defines a #define?
For example:
#define FID_STRS(x) #x
#define FID_STRE(x) FID_STRS(x)
#define FID_DECL(n, v) static int FIDN_##n = v;static const char *FIDS_##n = FID_STRE(v)
But instead:
#define FID_DECL2(n, v) #define FIDN_##n v \
FIDS_##n FID_STRE(v)
FID_DECL works fine but creates two static variables. Is it possible to make FID_DECL2 work and having define two defines?
No; preprocessing is performed in a single pass. If you want or need more advanced behavior, consider using another tool to preprocess the source, like m4.
Further, the # in the replacement list (at the beginning of #define FIDN... would be parsed as the # (stringize) operator: the operand of this operator must be a named macro parameter, which define is not.
No while defining macros u should take care of one thing
that macro should not call itself (reccursively) either directly
or indirectly.
I know two static variables consuming 8 bytes will be expansive for u.
I have solution over it
#define FID_STRS2(x) #x
#define FID_STRE(x) FID_STRS2(x)
#define FID_DECL(n, v) static int FIDN_##n = v;static const char *FIDS_##n = FID_STRE(v)
Just rename them going reccursive

Resources