Как использовать #ifdef внутри #define
Есть ли способ, которым я могу достичь этого
#define MAC(VAL , num)
#ifndef VAL \
int #VAL = num ; \
#define VAL \
#else \
#VAL = num ; \
#endif \
Я хочу определить VAL только один раз
1 ответ
Ответ не "Нет", я не смею сказать, что что-то невозможно с помощью макромагии.
Но ответ "не пытайся". потому что... см. комментарий RSahu.
И вот утомительный путь к этому ответу.
Самое близкое, что я получил (для VAL=MyInt и num=5):
#ifndef MyInt_flag
#define MyInt_flag
int
#endif
MyInt 5 = 5;
Обратите внимание, что нет (хорошо, я нашел) никакого способа использовать какой-либо макрос для фактического использования VAL и num абстрактно. Причины этого вы найдете ниже как "дерево неудачных попыток и обходных путей". Приглашаем всех найти хотя бы один более изящный способ решения любой из проблем, с которыми я столкнулся. Если все будет хорошо, я сделаю это вики.
Если вышеупомянутое является ближайшим решением к тому, что вы хотите, очень важно прочитать и продумать чрезвычайно ценный комментарий @RSahu.
Я перефразирую это, чтобы обеспечить другую точку зрения:
Если вам действительно удастся добиться того, что вы пытаетесь сделать, то у вас возникнут чрезвычайно неприятные проблемы, если вы сделаете это более чем в одном файле кода.
Цель определить переменную только один раз в нескольких файлах кода может быть достигнута только путем согласования одного и того же определения ее и использования только внешних ссылок на нее из других файлов кода.
Это потому, что компилятор и препроцессор не знают о содержимом других файлов кода.
Любые макросы, определенные в одном коде (или заголовках, которые он включает), неизвестны в других.
Только компоновщик (косвенно) знает об определениях языка C во всех файлах кода.
И именно линкер даст вам ошибки (или, что еще хуже, тихое поведение), которые вам не понравятся в конце.
Конец щедрой перефразировки @RSahu.
И, как еще одна точка зрения, резюме:
У вас будут большие и уродливые проблемы с этой концепцией, чем с чистым дизайном, где и где определяется переменная.
Хватит читать здесь, серьезно.
дерево неудачных попыток и обходных путей
Я изо всех сил старался подобраться как можно ближе к желаемому решению.
/* #define MAC(VAL, num) Does not work
... because you want to define a flag-macro
for keeping track of is-already-defined for each variable */
/* In order to use #define etc. inside the solution,
it needs to be in a header which gets included.
The following two "#define"s provide the quasi-parameters
VAL and num. This is needed before each use of said header. */
#define VAL MyInt
#define num 5
/* Imagine the rest of the solution below to be inside the
header "theheader.h". And do the corresponding
#include "theheader.h"
*/
#define VARFLAG(parVarId) parVarId##_flag
/* Just to deomstrate: */ char VARFLAG(VAL);
/*
#ifndef VARFLAG(VAL)
This fails with "warning: extra tokens at end of #ifndef directive"
#define VARFLAG(VAL)
#endif
You cannot test the definition of a parameterized macro.
*/
#ifndef VARFLAG
0;
#else
1;
/* This is the preprocessed result.
It does not have any dependency to VAL.
It just indicates, that a definition for VARFLAG
exists,
in this case for parameterized VARFLAG(parVarId).
*/
#endif
#ifdef VAL
2;
/* This is the preprocessed result.
No surprise, because the quasi-parameter is (should be defined
just before including "theheader.h"
*/
#else
3;
#endif
/* So lets skip using VAL and try the actual parameter "MyInt"
for the formal quasi-parameter VAL. */
#ifdef MyInt
4;
#else
5;
/* This is the preprocessed result,
becaue there is no macro of this name,
which at this point only happens to be a C-variable name,
unknown to the preprocessor.
You do not want to "just" define MyInt, i.e. without a body,
because that would kill all later attempts to use the variable.
I.e. do not do
#define MyInt
*/
#endif
#ifdef MyInt_flag
6;
#else /* of #ifdef MyInt_flag */
7;
/* This is the preprocessed result,
because there also is no macro of this name.
We will make sure later, that when MyInt gets defined
as a C-variable, MyInt_flag gets defined as a macro.
*/
/* Now define MyInt, using quasi-parameter VAL */
int VAL = num;
/* Preprocessed result is
int MyInt = 5;
*/
#ifdef MyInt
8;
#else
9;
/* This is the preprocessed result,
because only the C-variable exists, not the macro.
*/
#endif
/* Attempting to define MyInt_flag, using
#define VARFLAG(MyInt)
fails with a 'warning: "VARFLAG" redefined#.
So we have to do it the non-parameterized way.
Sorry, this is the first of the things that
are not possible more conveniently.
*/
#define MyInt_flag
#endif /* of #ifdef MyInt_flag #else ... */
/* Double-check,
sadly still not possible via
#ifdef VARFLAG(VAL)
neither via
#ifdef VARFLAG(MyInt)
so it has to be */
#ifdef MyInt_flag
10;
/* This at least is the preprocessed result,
because now there is a macro named "MyInt_flag".
*/
#else
11;
#endif
/* Now we can simulate the case of using "theheader.h"
in case the variable already is defined. */
#ifndef MyInt_flag
12;
/* representing all of above again,
but does not happen,
because the macro flag and the reflected C-variable
ARE defined */
#else
VAL = num;
13;
#endif
Вывод (gcc -E -P toy.c):
1;
2;
5;
7;
int MyInt = 5;
9;
10;
MyInt = 5;
13;