I'm trying to use multiple macros in the definition of another macro, but seem to have problems concatenating them together. Here's a very simplified version of what I'm trying to do:
#include <stdio.h>
#define PICK_SET_A
#ifdef PICK_SET_A
#define SET A
#endif
#ifdef PICK_SET_B
#define SET B
#endif
#define ENABLE_VAR_1_A 1
#define ENABLE_VAR_2_A 1
#define ENABLE_VAR_1_B 0
#define ENABLE_VAR_2_B 0
#define MACRO_RESOLVE(var,set) ENABLE_VAR_##var##_##set
#define ENABLE_VAR_1 MACRO_RESOLVE(1, SET)
#define ENABLE_VAR_2 MACRO_RESOLVE(2, SET)
int main(int argc, char **argv) {
fprintf(stdout, "VALUE: %d\n", ENABLE_VAR_1);
return 0;
}
I would expect the result to be 0.
However, I'm getting compile errors because the MACRO_RESOLVE macro isn't resolving the way I expect it to:
$ gcc -o asdf asdf.c
asdf.c:25:36: error: use of undeclared identifier 'ENABLE_VAR_1_SET'
fprintf(stdout, "VALUE: %d\n", ENABLE_VAR_1);
^
asdf.c:20:26: note: expanded from macro 'ENABLE_VAR_1'
#define ENABLE_VAR_1 MACRO_RESOLVE(1, SET)
^
asdf.c:18:32: note: expanded from macro 'MACRO_RESOLVE'
#define MACRO_RESOLVE(var,set) ENABLE_VAR_##var##_##set
^
<scratch space>:229:1: note: expanded from here
ENABLE_VAR_1_SET
^
1 error generated.
So it looks like SET isn't getting expanded when I define ENABLE_VAR_1.
Since you are trying to build a macro name, you need to do enough intermediate expansions along the way for all tokens to expand. See it live here.
#include <stdio.h>
#define PICK_SET_A
#ifdef PICK_SET_A
#define SET A
#endif
#ifdef PICK_SET_B
#define SET B
#endif
#define ENABLE_VAR_1_A 1
#define ENABLE_VAR_2_A 1
#define ENABLE_VAR_1_B 0
#define ENABLE_VAR_2_B 0
#define MACRO_RESOLVE__(M) M
#define MACRO_RESOLVE_(V, S) MACRO_RESOLVE__(ENABLE_VAR_ ## V ##_## S)
#define MACRO_RESOLVE(var,set) MACRO_RESOLVE_(var, set)
#define ENABLE_VAR_1 MACRO_RESOLVE(1, SET)
#define ENABLE_VAR_2 MACRO_RESOLVE(2, SET)
int main(int argc, char **argv) {
fprintf(stdout, "VALUE: %d\n", ENABLE_VAR_1);
return 0;
}
Related
A #define's replacement list containing no spaces can be mapped to integers (IDs):
#define ID_double 1
#define ID_float 2
#define ID_long_double 3
#define ID_(x) ID_##x
#define ID(x) ID_(x)
#define T double
T v;
int x = ID(T); /* 1 */
Now consider:
#define T long double
The code above won't compile:
<source>:3:25: error: 'ID_long' undeclared here (not in a function)
Question: is there a way to support spaces?
For example (somehow):
#define REPLACE_SPACES_TO_UNDERSCORES(x) ??
#define ID(x) ID_(REPLACE_SPACES_TO_UNDERSCORES(x))
#define T long double
T v;
int x = ID(T); /* 3 */
The same idea I had in Replace spaces with underscores in a macro? can also be used here, and the dictionary will be much more realistical in size. In the following code on the end, ID(T) is replaced by 3.
// dictionary
#define WORD_long long,
#define WORD_double double,
// ---------------------------------------------
// the classics
#define COMMA(...) ,
#define FIRST(a, ...) a
// apply function f for each argument recursively with tail
#define FOREACHTAIL_1(f,a) f(a,)
#define FOREACHTAIL_2(f,a,...) f(a,FOREACHTAIL_1(f,__VA_ARGS__))
#define FOREACHTAIL_3(f,a,...) f(a,FOREACHTAIL_2(f,__VA_ARGS__))
#define FOREACHTAIL_4(f,a,...) f(a,FOREACHTAIL_3(f,__VA_ARGS__))
#define FOREACHTAIL_N(_4,_3,_2,_1,N,...) \
FOREACHTAIL_##N
#define FOREACHTAIL(f,...) \
FOREACHTAIL_N(__VA_ARGS__,4,3,2,1)(f,__VA_ARGS__)
// if there are two arguments, expand to true. Otherwise false.
#define IFTWO_N(_0,_1,N,...) N
#define IFTWO(true, false, ...) IFTWO_N(__VA_ARGS__, true, false)
// If empty, expand to true, otherwise false.
// https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
#define IFEMPTY(true, false, ...) IFTWO(true, false, COMMA __VA_ARGS__ ())
// Join arguments with `_`.
#define JOIN_U(a, b) a##_##b
#define JOIN_TWO_IN(a,b) IFEMPTY(FIRST, JOIN_U, b)(a, b)
#define JOIN_TWO(a,b) JOIN_TWO_IN(a,b)
#define JOIN(...) FOREACHTAIL(JOIN_TWO, __VA_ARGS__)
// Append WORD_ to each argument and join arguments with spaces.
#define WORD_ /* the last one expands to empty */
#define WORDS_TWO(a, b) WORD_##a b
#define WORDS(...) FOREACHTAIL(WORDS_TWO, __VA_ARGS__)
#define REPLACE_SPACES_TO_UNDERSCORES(a) JOIN(WORDS(WORDS(WORDS(WORDS(WORDS(a))))))
// --------------------------------------------
#define ID_double 1
#define ID_float 2
#define ID_long_double 3
#define ID_IN2(x) ID_##x
#define ID_IN(x) ID_IN2(x)
#define ID(x) ID_IN(REPLACE_SPACES_TO_UNDERSCORES(x))
int main() {
#define T long double
T v;
int x = ID(T); /* 3 */
}
Is there a way to define a macro that voids variable list of arguments?
#define VOID_ARGS(...) ((void)##__VA_ARGS__)
The use case is void arguments to suppress compiler error [-Werror=unused-value] when warnings treated as errors:
#define DEBUG 1
#ifdef DEBUG
#define func(fmt, ...) dbg_func(fmt, ##__VA_ARGS__)
#else
#define func(fmt, ...) VOID_ARGS(fmt, ##__VA_ARGS__)
#endif
Does this give you an idea how to solve that problem?
debug.h:
extern int dbg_func(const char *format, ...);
//Does nothing
extern int ignoreDebug(const char *format, ...);
#define DEBUG 1
#ifdef DEBUG
#define func(fmt, ...) dbg_func(fmt, ##__VA_ARGS__)
#else
#define func(fmt, ...) ignoreDebug(fmt, ##__VA_ARGS__)
#endif
debug.c:
int ignoreDebug(const char *format, ...)
{
(void)format;
return 0;
}
int dbg_func(const char *format, ...)
{
TODO: Some code needs to go here.
return 0;
}
Rather than attempting to put the debug logic in the function declaration, add it to the function body instead:
int dbg_func(const char *format, ...)
{
#ifdef DEBUG
// normal debug logic
#else
(void)format;
return 0;
#endif
}
I found a way only using the processor. The idea came from this answer https://stackoverflow.com/a/11763277/6082851 The idea is to define a bunch of macros that void the arguments, one macro per possible number of arguments. With the use of __VA_ARGS__, the correct macro can be chosen depending on the number of arguments. Sadly, i didn't found a way to make it recursive so that a limited number of macros can be used for an arbitrary number of arguments, the only way i found was to define a macro for each possible number of arguments. But it can be expanded to an arbitrary amount.
#include <stdio.h>
#ifndef DEBUG
#define DEBUG 1
#endif
#if DEBUG
#define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)
#else
//GET_MACRO will get the 6. argument
#define GET_MACRO(a,b,c,d,e,f,...) f
//Macros that void a number of arguments
#define SET_VOID0()
#define SET_VOID1(a) (void)a;
#define SET_VOID2(a,b) (void)a;(void)b;
#define SET_VOID3(a,b,c) (void)a;(void)b;(void)c;
#define SET_VOID4(a,b,c,d) (void)a;(void)b;(void)c;(void)d;
#define SET_VOID5(a,b,c,d,e) (void)a;(void)b;(void)c;(void)d;(void)e;
//Void all arguments to avoid compiler warnings.
//SET_VOID5 is used when there are 5 arguments used, SET_VOID4 when 4 are used, ...
#define DEBUG_PRINT(...) GET_MACRO(__VA_ARGS__, SET_VOID5, SET_VOID4, SET_VOID3, SET_VOID2, SET_VOID1, SET_VOID0)(__VA_ARGS__)
#endif
int main(void)
{
int foo=5;
int bar=3;
DEBUG_PRINT("Foo %i Bar %i\n",foo,bar);
return 0;
}
I want to create a define using macro expansion. The crated define shall hold the value of an other define. :)
Example:
#define ONE 1
#define TWO 2
#define MACRO(x, y) ...
...
#define MACRO_1_2 3
My question is: how can I resolve / use the value of a define in macro expansion?
I have tried to use
#define TEST_MACRO_V2(x, y) TEST_MACRO_V2_"x"_"y"
, but I get the following error:
main.c:18:34: error: ‘TEST_MACRO_V2_’ undeclared (first use in this function)
#define TEST_MACRO_V2(x, y) TEST_MACRO_V2_"x"_"y"
My test code:
#include <stdio.h>
#define ONE 1
#define TWO 2
#define TEST_MACRO_V1(x, y) TEST_MACRO_V1_##x##_##y
#define TEST_MACRO_V1_ONE_TWO 3
//#define TEST_MACRO_V2(x, y) TEST_MACRO_V2_##('x')##_##('y') -> this version does not work
#define TEST_MACRO_V2(x, y) TEST_MACRO_V2_"x"_"y"
#define TEST_MACRO_V2_1_2 4
int main()
{
printf("Test Macro V1: %d\n", TEST_MACRO_V1(ONE, TWO));
printf("Test Macro V2: %d\n", TEST_MACRO_V2(ONE, TWO));
return 0;
}
Note: TEST_MACRO_V1 works fine. I need TEST_MACRO_V2.
I tried this on ideone.com:
#include <stdio.h>
#define ONE 1
#define TWO 2
#define TEST_MACRO_HELPER(x, y) TEST_MACRO_##x##_##y
#define TEST_MACRO(x, y) TEST_MACRO_HELPER(x, y)
#define TEST_MACRO_1_2 4
int main()
{
printf("Test Macro: %d\n", TEST_MACRO(ONE, TWO));
return 0;
}
Output:
Test Macro: 4
I'm trying to write definitions for AVR C code so that i can access pins by simmple macro like
STATUS_LED_OUT =1;
in GENET_HW_DEF.h file, included to main C file. You can reproduce this bug by including this file into any C project.
I'm using avr studio 6.2 and 7 - both give the same result. I cannot compile getting werid macro unfold message like below. (CPU ATMega1284p)
D:\_SVN\Compass\AVR\Compass_IO_proto\Compass IO_proto\GENET_HW_DEF.h(19,49): error: expected ')' before '&' token
#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt
^
D:\_SVN\Compass\AVR\Compass_IO_proto\Compass IO_proto\GENET_HW_DEF.h(42,25): info: in expansion of macro 'REGISTER_BIT'
#define STATUS_LED_OUT REGISTER_BIT(PORTB,7)
^
D:\_SVN\Compass\AVR\Compass_IO_proto\Compass IO_proto\GENET_HW_DEF.h(46,2): info: in expansion of macro 'STATUS_LED_OUT'
STATUS_LED_OUT=1;
^
Interesting enough, copied to fresh project with just only one or two declarations compiles fine, until one makes any changes in the declarations - like adding another macro reference. Then it becomes stuck again.
Also - if i comment all macro usages like
STATUS_LED_DIR=1;
STATUS_LED_OUT=1;
then I'm able to compile project and then after uncommenting usage lines it still compiles fine.. untill clean is executed. I'm probably messing with macro quirks but I have no idea where.
typedef struct
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
unsigned int bit4:1;
unsigned int bit5:1;
unsigned int bit6:1;
unsigned int bit7:1;
} _io_reg;
#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt
#ifndef GENET_HW_DEF
#define GENET_HW_DEF
// define functionalities and flags - comment/uncomment apropriate lines
#define GENET_USART_0 256
#define GENET_USART_1 256
#define F_CPU 20000000UL
#define STATUS_LED 7
#define ERROR_LED 4
#define ADC_GLOBAL_ENABLE A
#define ADC_CHANNEL_0 0
#define ADC_CHANNEL_1 4
#define ADC_CHANNEL_2 2
#define ADC_CHANNEL_3 3
#define ADC_CHANNEL_4 1
#define ADC_CHANNEL_5 5
#define ADC_CHANNEL_6 6
#define ADC_CHANNEL_7 7
// actual definitions and initialization
#ifdef STATUS_LED
#define STATUS_LED_OUT REGISTER_BIT(PORTB,STATUS_LED)
#define STATUS_LED_DIR REGISTER_BIT(DDRB,STATUS_LED)
#define STATUS_LED_PIN REGISTER_BIT(PINB,STATUS_LED)
STATUS_LED_DIR=1;
STATUS_LED_OUT=1;
#endif
#ifdef ERROR_LED
#define ERROR_LED_OUT REGISTER_BIT(PORTC,ERROR_LED)
#define ERROR_LED_DIR REGISTER_BIT(DDRC,ERROR_LED)
ERROR_LED_DIR=1;
ERROR_LED_OUT=1;
#endif
#ifdef GENET_USART_0
#define USART0_ENABLED
#define UART_RX0_BUFFER_SIZE GENET_USART_0
#define UART_TX0_BUFFER_SIZE GENET_USART_0
#endif
#ifdef GENET_USART_1
#define USART1_ENABLED
#define UART_RX1_BUFFER_SIZE GENET_USART_1
#define UART_TX1_BUFFER_SIZE GENET_USART_1
#endif
#endif
I reproduced your problem.
You cannot call STATUS_LED_DIR=1; outside code execution flow. This must be inside a function (for example main()).
Now you will end with other compilation errors but this was the main mistake.
Second correction, you need 2 level for concatenation
#define CONCAT(bt) bit##bt
#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->CONCAT(bt)
#include <stdio.h>
#define LOG_D(x) { printf("D:"); printf(x);}
#define LOG_E(x) { printf("E:"); printf(x);}
void test(void)
{
LOG_D("ALL is well " );
}
I have a very huge code it has different levels of log, like above code.
In the final tested library I just need only one error logs in order to reduce the code size .
so I want something like this
#define ENABLE_DEBUG_LOG 0
#define ENABLE_ERROR_LOG 1
#define LOG_D(x) {#if(ENABLE_DEBUG_LOG==1) printf("D:"); printf(x); #endif}
#define LOG_E(x) {#if(ENABLE_ERROR_LOG==1) printf("E:"); printf(x);#endif}
I added this #if(ENABLE_DEBUG_LOG==1) just for explaining, I need some solution which can compile.
Another option - you can just comment / uncomment ENABLE_DEBUG_LOG and ENABLE_ERROR_LOG to disable / enable corresponding log level.
// #define ENABLE_DEBUG_LOG // disable DEBUG_LOG
#define ENABLE_ERROR_LOG // enable ERROR_LOG
#ifdef ENABLE_DEBUG_LOG
#define LOG_D(x) { printf("D:"); printf(x);}
#else
#define LOG_D(x) // nothing
#endif
#ifdef ENABLE_ERROR_LOG
#define LOG_E(x) { printf("E:"); printf(x);}
#else
#define LOG_E(x) // nothing
#endif
You cannot nest preprocessor directives. But you can make two versions of your macro and define them in exclusive parts of an #if or #ifdef:
#define ENABLE_DEBUG_LOG 0
#if ENABLE_DEBUG_LOG != 0
#define LOG_D(...) printf("D: " __VA_ARGS__)
#else
#define LOG_D(...) // Do nothing
#endif
Here, the disabled version just "eats" the LOG_D macro and doesn't do anything. (Note that undefined macros are treated as the value 0 in #if conditionals.)
You should be able to do something like this:
#if ENABLE_DEBUG_LOG == 1
# define LOG_D(x) { printf("D:"); printf(x);}
#else
# define LOG_D(x)
#end
That way the debug log statements will just disappear if ENABLE_DEBUG_LOG is undefined or has a different value.
Regarding the other answers, it is not good idea to define the macros completely empty when they are not enabled, as this would go wrong when error logging is enabled:
if (some_error)
LOG_E("Oops...");
do_something();
If LOG_E(x) expands to nothing, then do_something() would only be called if some_error is true, which is probably not what you want!
So you could define the "do nothing" variant of LOG_E(x) like this:
#define LOG_E(x) { }
Rather than starting and ending with braces, I tend to use the do { blah; } while (0) construct as it forces you to put a semicolon on the end when you use it. Something like this:
#if ENABLE_ERROR_LOG
#define LOG_E(x) do { printf("E:"); printf(x); } while (0)
#else
#define LOG_E(x) do ; while (0)
#endif
Then,
if (some_error)
LOG_E("Oops")
would result in a syntax error because of the missing semicolon, forcing you to write it as
if (some_error)
LOG_E("Oops");
Another thing you can do is concatenate the "E:" or "D:" tag with the passed in string, although this requires the parameter to be a string literal, rather than a general char *:
#define LOG_E(x) printf("E:" x)
Another thing you can do is to define the macro with a variable number of parameters (a variadic macro) to increase your options:
#define LOG_E(...) printf("E:" __VA_ARGS__)
Then you can do:
if (some_error)
LOG_E("Oops, got error: %d\n", some_error);
Another thing you can do is let the compiler optimize out the call to printf and define it like this:
#define LOG_E(...) do if (ENABLE_ERROR_LOG) printf("E:" __VA_ARGS__); while (0)
A decent compiler will notice that the if condition is constant and either optimize out the call to printf completely (if the constant condition is false), or include it (if the constant condition is true). For some compilers, you might need to suppress warnings about constant conditions in an if statement.
I am not sure if this is what you want, but you could check the #ifdef directive.
#include <stdio.h>
/* #define DEBUG */
#ifdef DEBUG
#define LOG_D(x) { printf("D: %s\n",x); }
#define LOG_E(x) { printf("E: %s\n",x); }
#else
#define LOG_D(x)
#define LOG_E(x)
#endif
int main() {
LOG_D("blah...");
return 0;
}
If you uncomment the #define DEBUG line, the program will print D: blah...