Как использовать #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;
Другие вопросы по тегам