как использовать #ifdef внутри #define

есть ли способ, которым я могу этого достичь

#define MAC(VAL , num)
#ifndef VAL 
int #VAL = num ; 
#define VAL 
#else 
#VAL = num ; 
#endif 

Я хочу определить VAL только один раз

1 ответ

  1. Ответ Не «Нет», я не смею сказать что-то невозможное с макро-магией.
    Но ответ: «Не пытайтесь.» потому что. .. см. комментарий RSahu.

    И вот нудный путь к этому ответу.
    Ближе всего я получил (для VAL=MyInt и num=5) :

    #ifndef MyInt_flag
    #define MyInt_flag
    int
    #endif
    MyInt 5 = 5;
    

    Обратите внимание, что нет (Хорошо, я нашел) никакого способа использования любого макроса на самом деле использовать val и num абстрактно. Причины этого вы найдете ниже как «дерево неудачных попыток и обходных путей». Всем предлагается найти хотя бы один немного более элегантный обходной путь для любой из проблем, с которыми я столкнулся. Если это будет хорошо, я сделаю это wiki.

    Если это ближайшее решение для того, что вы хотите, очень важно прочитать и продумать чрезвычайно ценный комментарий @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.с):

    1;
    2;
    5;
    7;
    int MyInt = 5;
    9;
    10;
    MyInt = 5;
    13;