代码之家  ›  专栏  ›  技术社区  ›  Daniel LeCheminant

使用ifdefs和define可以选择将函数调用转换为注释。

  •  14
  • Daniel LeCheminant  · 技术社区  · 17 年前

    可以这样做吗

    #ifdef SOMETHING
    #define foo //
    #else
    #define foo MyFunction
    #endif
    

    其思想是,如果定义了某个内容,那么对foo(…)的调用将变为注释(或者不进行计算或编译的内容),否则它将变为对myfunction的调用。

    我见过努普用过,但我不相信我能用。

    编辑(S):

    我认为我不能在这里真正使用宏,因为MyFunction接受的参数数目是可变的。

    另外,我想让它这样的论点不会被评估!(因此,做一些类似于注释MyFunction主体的事情并不能真正满足我的需要,因为参数仍将被评估)

    11 回复  |  直到 11 年前
        1
  •  24
  •   community wiki 10 revs, 2 users 62% ChrisW    9 年前

    试试这个:

    #ifdef SOMETHING
    #define foo(x)
    #else
    #define foo(x) MyFunction(x)
    #endif
    

    如果函数有几个参数,则:

    #ifdef SOMETHING
    #define foo(x,y,z)
    #else
    #define foo(x,y,z) MyFunction(x,y,z)
    #endif
    

    如果函数的参数数目可变,则编译器可能支持所谓的“variadic宏”,如下所示:

    #ifdef SOMETHING
    #define foo(...)
    #else
    #define foo(...) MyFunction(__VA_ARGS__)
    #endif
    

    我看到在实践中使用这种方法的原因是为了从发布版本中去掉日志记录函数。但是,另请参见 Separate 'debug' and 'release' builds? 在这里人们质疑你 应该 即使 不同的版本。


    或者,Jonathan对这个答案的评论并没有将函数调用重新定义为Nothing,而是建议您执行如下操作:

    #ifdef SOMETHING
    #define foo(...) do { if (false) MyFunction(__VA_ARGS__) } while (0)
    #else
    #define foo(...) do { if (true) MyFunction(__VA_ARGS__) } while (0)
    #endif
    

    这样做的原因是,函数调用总是被编译的(这样它就不会留下诸如对已删除变量的引用之类的无意义的错误),但只在需要时调用:请参阅kernighan&pike The Practice of Programming 还有 Goddard Space Flight Center programming standards .

    来自debug.h文件(源自1990年,因此不使用 __VA_ARGS__ ):

    /*
    ** Usage:  TRACE((level, fmt, ...))
    ** "level" is the debugging level which must be operational for the output
    ** to appear. "fmt" is a printf format string. "..." is whatever extra
    ** arguments fmt requires (possibly nothing).
    ** The non-debug macro means that the code is validated but never called.
    ** -- See chapter 8 of 'The Practice of Programming', by Kernighan and Pike.
    */
    #ifdef DEBUG
    #define TRACE(x)    db_print x
    #else
    #define TRACE(x)    do { if (0) db_print x; } while (0)
    #endif /* DEBUG */
    

    有了c99,就不再需要双括号技巧了。除非C89兼容性存在问题,否则新代码不应使用它。

        2
  •  5
  •   MattK    17 年前

    也许一个更简单的方法是有条件地省略函数体?

    void MyFunction() {
    #ifndef SOMETHING
        <body of function>
    #endif
    }
    

    除非您特别不希望进行函数调用,否则这似乎是实现目标的一种干净方法。

        3
  •  3
  •   Iraimbilanja    17 年前

    不幸的是,当前的C++版本不支持变量宏。

    但是,您可以这样做:

    #ifdef SOMETHING
    #define foo
    #else
    #define foo(args) MyFunction args
    #endif
    
    // you call it with double parens:
    foo((a, b, c));
    
        4
  •  2
  •   Ferruccio    17 年前

    如果不希望调用foo,则将其定义为:

    void foo() {}
    

    对foo()的任何调用都应该是优化的方式。

        5
  •  2
  •   Christoph    17 年前

    沿着这条线做些什么:

    #ifdef NDEBUG
    #define DEBUG(STATEMENT) ((void)0)
    #else
    #define DEBUG(STATEMENT) (STATEMENT)
    #endif
    

    您可以这样使用它来记录调试消息:

    DEBUG(puts("compile with -DNDEBUG and I'm gone"));
    

    使用c99可变宏和 __func__ 标识符可能如下所示:

    #ifdef NDEBUG
    #define Dprintf(FORMAT, ...) ((void)0)
    #define Dputs(MSG) ((void)0)
    #else
    #define Dprintf(FORMAT, ...) \
        fprintf(stderr, "%s() in %s, line %i: " FORMAT "\n", \
            __func__, __FILE__, __LINE__, __VA_ARGS__)
    #define Dputs(MSG) Dprintf("%s", MSG)
    #endif
    

    以下是使用这些宏的方法:

    Dprintf("count = %i", count);
    Dputs("checkpoint passed");
    
        6
  •  2
  •   slacy    17 年前

    很可能,您不想按照建议进行简单的“代码删除”, 因为您的呼叫者将期待 会发生争论。以下是一些麻烦的调用程序片段 应该让你思考:

    // pre/post increment inside method call:
    MyFunction(i++); 
    
    // Function call (with side effects) used as method argument: 
    MyFunction( StoreNewUsernameIntoDatabase(username) ); 
    

    如果你只是说:

    #define MyFunction(x) 
    

    打电话的人所期望的副作用就会消失, 它们的代码会中断,并且很难调试。我喜欢 上面的“sizeof”建议,我也喜欢这样的建议 通过ifdef禁用myfunction()的主体,尽管这意味着 所有调用方都获得相同版本的myFunction()。从你 问题陈述,我想这不是你想要的。

    如果确实需要通过上的预处理器定义禁用myfunction()。 基于每个源文件,然后我会这样做:

    #ifdef SOMETHING 
    #define MyFunction(x) NoOp_MyFunction(x) 
    
    int NoOp_MyFunction(x) { } 
    #endif 
    

    甚至可以在内部包含noop_MyFunction()的实现 myFunction()的源&头。你也有灵活性 在noop_MyFunction()中添加额外的日志记录或调试信息 好。

        7
  •  1
  •   anon    17 年前

    不,C和C++标准说你不能定义一些东西作为评论,所以

    #define foo //
    

    不起作用。

        8
  •  1
  •   MSN    17 年前
    #ifdef SOMETHING
    #define foo sizeof
    #else
    #define foo MyFunction
    #endif
    

    我假设foo是 printf 样式功能?无论如何,这不适用于零参数函数,但是如果是这样的话,您就已经知道该怎么做了。如果你真的想做肛门,你可以用 (void)sizeof 但这可能是不必要的。

        9
  •  1
  •   Michael Burr    17 年前

    我有点不愿意发布这个答案,因为使用宏黑客可以成为问题的根源。然而- 如果 对您希望消失的函数的调用总是单独用于语句中(即,它们从来不是更大表达式的一部分),然后类似以下内容的调用可以工作(它处理varargs):

    #ifdef SOMETHING
    #define foo (1) ? ((void) 0) : (void)
    #else
    #define foo MyFunction
    #endif
    

    所以如果你有代码行:

    foo( "this is a %s - a++ is %d\n", "test", a++);
    

    它将在预处理步骤之后作为以下任一步骤结束:

    MyFunction( "this is a %s - a++ is %d\n", "test", a++);
    

    (1) ? ((void) 0) : (void)( "this is a %s - a++ is %d\n", "test", a++);
    

    它将伪函数的参数列表转换为一组表达式,这些表达式由逗号运算符分隔,而逗号运算符永远不会被计算,因为条件总是返回 ((void) 0) 结果。

    这种情况的一个变种类似于Chrisw和Jonathan Leffler的建议:

    #ifdef SOMETHING
    #define foo if (0) MyFunction
    #else
    #define foo if (1) MyFunction
    #endif
    

    这有点不同,因为它不需要编译器支持可变宏。( __VA_ARGS__ )

    我认为这对于消除调试跟踪函数调用很有用,这些调用通常不会组合成更大的表达式,但除此之外,我认为这是一种危险的技术。

    注意潜在的问题-特别是当调用中的参数产生副作用时(这是宏的一个一般问题-不仅仅是这个黑客)。在示例中, a++ 只有当 SOMETHING 是在生成中定义的,否则不是。因此,如果调用后的代码取决于 a 要递增,其中一个构建有一个bug。

        10
  •  0
  •   Mike Dinescu    17 年前

    如果我记得正确,您应该能够将宏定义为“Nothing”,这将导致编译器忽略该调用。

    #define foo()
    
    foo();    // this will be ignored
    
        11
  •  0
  •   Brian Postow    17 年前

    用什么包围每个调用MyFunction?

    #ifdef SOMETHING
    myFunction(...);
    #endif
    

    ?