如何在#define中使用#ifdef

时间:2016-05-24 15:00:28

标签: c c-preprocessor

有没有办法实现这个目标

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

我想只定义一次VAL

1 个答案:

答案 0 :(得分:0)

答案不是"不是",我不敢说宏观魔法是不可能的。
但答案是"不要尝试。"因为...见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;