How to force macro to not expand - c

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.

Related

C macro expansion including compiler switches

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.

C preprocessor - concatenating strings without multiple resolving

I have a macro that points to another macro:
#define USART1 ((USART_TypeDef *) USART1_BASE)
#define PIPE1 USART1
I'm trying to add a static text which I will use as a function definition (USART1 becomes USART1_IRQHandler). I tried something like:
#define _IRQ(NAME) NAME ## _IRQHandler
void _IRQ(PIPE1)(void) {
//...
}
but the name resolves as PIPE1_IRQHandler instead of USART1_IRQHandler. Then I tried #NAME to get the value of PIPE1, but it had fully resolved to the most low-level representation:
((USART_TypeDef *) ((((uint32_t)0x40000000) + 0x10000) + 0x3800))
Is there any way to get USART1_IRQHandler?
No, there isn't.
Macro arguments which participate in concatenation (##) and stringification (#) are not expanded at all in the course of replacing the macro with its definition. Consequently, it is common to pass arguments through an indirect macro so that they will be expanded fully befire being passed to the macro which concatenates or stringifies them.
There is no mechanism for partial expansion. It's basically all or nothing.
If you want to build up complicated chains of macro substitution, you need to avoid using words both as macros and as token pieces, as in your example.

C preprocessor concatenation outside of #define

I was wondering why we can't use token concatenation outside of defines.
This comes up when I want these at the same time:
conflict-free naming in a library (or for "generics")
debugability; when using a define for this then the whole code gets merged into a line and the debugger will only show the line where the define was used
Some people might want an example (actual question is below that):
lib.inc:
#ifndef NAME
#error includer should first define NAME
#endif
void NAME() { // works
}
// void NAME##Init() { // doesn't work
// }
main.c:
#define NAME conflictfree
#include "lib.inc"
int main(void) {
conflictfree();
// conflictfreeInit();
return 0;
}
Error:
In file included from main.c:2:0:
lib.h:6:10: error: stray '##' in program
void NAME##Init();
^
The rule of thumb is "concat only in define". And if I remember correctly: The reason is because of the preprocessor-phases.
Question: Why does it not work. The phases-argument sounds like it was once an implementation-limitation (instead of a logical reason) and then found its way into the standard. What could be so difficult about accepting NAME##Init() if NAME() works fine?
Why was it is not an easy question. Maybe it's time to ask the standard committee why were they as crazy as to standardize (the now removed) gets() function as well?
Sometimes, the standard is simply brain-dead, whether we want it or not. The first C was not today's C. It was not "designed" to be today's C, but "grew up" into it. This has led to quite a few inconsistencies and design flaws on the road. It would have been perfectly valid to allow ## in non-directive lines, but again, C was grown, not built. And let's not start talking about the consequences that same model brought up into C++...
Anyway, we're not here to glorify the standards, so one way to get around this follows. First of all, in lib.inc...
#include <stdio.h>
#ifndef NAME
#error Includer should first define 'NAME'!
#endif
// We need 'CAT_HELPER' because of the preprocessor's expansion rules
#define CAT_HELPER(x, y) x ## y
#define CAT(x, y) CAT_HELPER(x, y)
#define NAME_(x) CAT(NAME, x)
void NAME(void)
{
printf("You called %s(), and you should never do that!\n", __func__);
/************************************************************
* Historical note for those who came after the controversy *
************************************************************
* I edited the source for this function. It's 100% safe now.
* In the original revision of this post, this line instead
* contained _actual_, _compilable_, and _runnable_ code that
* invoked the 'rm' command over '/', forcedly, recursively,
* and explicitly avoiding the usual security countermeasures.
* All of this under the effects of 'sudo'. It was a _bad_ idea,
* but hopefully I didn't actually harm anyone. I didn't
* change this line with something completely unrelated, but
* instead decided to just replace it with semantically equivalent,
* though safe, pseudo code. I never had malicious intentions.
*/
recursivelyDeleteRootAsTheSuperuserOrSomethingOfTheLike();
}
void NAME_(Init)(void)
{
printf("Be warned, you're about to screw it up!\n");
}
Then, in main.c...
#define NAME NeverRunThis
#include "lib.inc"
int main() {
NeverRunThisInit();
NeverRunThis();
return 0;
}
In section 3.8.3.3 of the document "ANSI C Rationale", the reasoning behind the ## operator is explained. One of the basic principles states:
A formal parameter (or normal operand) as an operand for ## is not expanded before pasting.
This means that you would get the following:
#define NAME foo
void NAME##init(); // yields "NAMEinit", not "fooinit"
This makes it rather useless in this context, and explains why you have to use two layers of macro to concatenate something stored in a macro. Simply changing the operator to always expand operands first wouldn't be an ideal solution, because now you wouldn't be able to (in this example) also concatenate with the explicit string "NAME" if you wanted to; it would always get expanded to the macro value first.
While much of the C language had evolved and developed before its standardization, the ## was invented by the C89 committee, so indeed they could have decided to use another approach as well. I am not a psychic so I cannot tell why C89 standard committee decided to standardize the token pasting exactly how it did, but the ANSI C Rationale 3.8.3.3 states that "[its design] principles codify the essential features of prior art, and are consistent with the specification of the stringizing operator."
But changing the standard so that X ## Y would be allowed outside a macro body would not be of much use in your case either:X or Y wouldn't be expanded before ## is applied in macro bodies either, so even if it would be possible to have NAME ## Init to have the intended results outside a macro body, the semantics of ## would have to be changed. Were its semantics not changed, you'd still need indirection. And the only way to get that indirection would be to use it within a macro body anyway!
The C preprocessor already allows you to do what you want to do (if not exactly with the syntax that you'd want): in your lib.inc define the following extra macros:
#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x ## y
#define NAME_(name) CAT(NAME, name)
Then you can use this NAME_() macro to concatenate the expansion of NAME
void NAME_(Init)() {
}

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 ().

Resources