繁体   English   中英

`#ifdef` 可以在宏中使用吗?

[英]Can `#ifdef` be used inside a macro?

我只找到了这个相关的问题,这不是我想要的。

我曾经在#ifdef语句中定义了宏:

#ifdef DEBUG
#   define PRINT_IF_DEBUGGING(format) printf(format);
#   define PRINTF_IF_DEBUGGING(format, ...) printf(format, __VA_ARGS__);
#else
#   define PRINT_IF_DEBUGGING(...)
#   define PRINTF_IF_DEBUGGING(...)
#endif

现在,我想做相反的事情,在宏中包含#ifdef语句。 像这样的东西:

#define PRINT_IF_DEBUGGING(format, ...) \
#if defined(DEBUG) print(format); #endif
#define PRINTF_IF_DEBUGGING(format, ...) \
#if defined(DEBUG) printf(format, __VA_ARGS__); #endif

但是,我在#ifdef defined中使用__VA_ARGS__时遇到问题。

error: '#' is not followed by a macro parameter
 #define PRINT_IF_DEBUGGING(format, ...)
error: '#' is not followed by a macro parameter
 #define PRINTF_IF_DEBUGGING(format, ...)
warning: __VA_ARGS__ can only appear in the expansion of a C++11 variadic macro
 #if defined(DEBUG) printf(format, __VA_ARGS__); #endif

这可能吗?

这确实应该是一个评论,但我无法以一种允许我说出我想说的话的方式来格式化它,所以我正在回答。

无论如何,只要改变这个:

#if defined(DEBUG) print(format); #endif

对此:

#if defined(DEBUG)
    print(format);
#endif

等等,这应该可以解决它。

您不能#define中使用#ifdef ,所以不,这是不可能的。 您显示的第一个代码是正确的解决方案。

#define中使用#ifdef是不可能的。 但是仍有一些方法可以检测宏定义中是否定义了宏。

1.解决方案

神螺栓

#define CAT(a, b) CAT_IMPL(a, b)
#define CAT_IMPL(a, b) a ## b

#define IS_DEBUG_DEFINED() CHECK((CAT(CHECK_,DEBUG), 0, 1))
#define CHECK_DEBUG ~,~
#define CHECK(tup) CHECK_IMPL tup
#define CHECK_IMPL(a, b, c, ...) c

#define IIF(condition, true_value, false_value) CAT(IIF_,condition)(true_value, false_value)
#define IIF_0(true_value, false_value) false_value
#define IIF_1(true_value, false_value) true_value 

#define PRINT_IF_DEBUGGING(format) IIF(IS_DEBUG_DEFINED(), PRINT_DEBUGGING, PRINT_NOT_DEBUGGING)(format)
// this will be used if DEBUG is defined:
#define PRINT_DEBUGGING(format) debugPrint(format)
// this will be used if DEBUG is NOT defined:
#define PRINT_NOT_DEBUGGING(format) print(format)

PRINT_IF_DEBUGGING(foo)将扩展为:

  • 如果定义了DEBUGdebugPrint(foo)
  • 如果未定义DEBUGprint(foo)

例子:

PRINT_IF_DEBUGGING("test1");

#define DEBUG
PRINT_IF_DEBUGGING("test2");
#undef DEBUG

PRINT_IF_DEBUGGING("test3");

会导致:

print("test1");

debugPrint("test2");

print("test3");

2. IS_DEBUG_DEFINED()是如何工作的

这背后的基本技巧是使用连接- 如果定义了宏,它将被扩展,否则预处理器不会修改标记:

神螺栓

#define CAT(a, b) CAT_IMPL(a, b)
#define CAT_IMPL(a, b) a ## b

// DEBUG NOT DEFINED:
CAT(CHECK_,DEBUG) // will expand to CHECK_DEBUG

// DEBUG DEFINED:
#define DEBUG 1234
CAT(CHECK_,DEBUG) // will expand to CHECK_1234
  • 第一个CAT将扩展为CHECK_DEBUG ,因为未定义DEBUG
  • 然而,第二个CAT将扩展为CHECK_1234 ,因为DEBUG在与CHECK_连接之前已定义并扩展为1234

通过定义一个名为CHECK_DEBUG的宏,如果未定义该宏,我们可以更改结果,例如:

神螺栓

#define TEST CAT(CHECK_,DEBUG), 0, 1
#define CHECK_DEBUG ~,~
  • 如果未定义DEBUG ,则结果将为~, ~, 0, 1 ( 4 个逗号分隔的标记)
  • 如果定义了DEBUG ,则结果将为CHECK_, 0, 13 个逗号分隔的标记)

注意我们在第一种情况下是如何得到 4 个令牌的,但在第二种情况下只有 3 个令牌。

现在我们需要做的就是从该序列中获取第三个标记(如果未定义DEBUG ,则为0 ,否则为1 ),例如使用始终返回第三个参数的简单宏:

#define CHECK(a, b, c, ...) c

综上所述,这就是完整的IS_DEBUG_DEFINED()的样子:

神螺栓

#define CAT(a, b) CAT_IMPL(a, b)
#define CAT_IMPL(a, b) a ## b

#define IS_DEBUG_DEFINED() CHECK((CAT(CHECK_,DEBUG), 0, 1))
#define CHECK_DEBUG ~,~
#define CHECK(tup) CHECK_IMPL tup
#define CHECK_IMPL(a, b, c, ...) c

如果未定义DEBUGIS_DEBUG_DEFINED()将扩展为0 ,如果是,则扩展为1 ,例如:

IS_DEBUG_DEFINED() // -> 0

#define DEBUG
IS_DEBUG_DEFINED() // -> 1
#undef DEBUG

IS_DEBUG_DEFINED() // -> 0

使用IS_DEBUG_DEFINED() ,您可以使用标准预处理器IIF来更改宏的行为,具体取决于是否定义了DEBUG

示例:神螺栓

#define IIF(condition, true_value, false_value) CAT(IIF_,condition)(true_value, false_value)
#define IIF_0(true_value, false_value) false_value
#define IIF_1(true_value, false_value) true_value 

#define PRINT_IF_DEBUGGING(format) IIF(IS_DEBUG_DEFINED(), PRINT_DEBUGGING, PRINT_NOT_DEBUGGING)(format)
// this will be used if DEBUG is defined:
#define PRINT_DEBUGGING(format) debugPrint(format)
// this will be used if DEBUG is NOT defined:
#define PRINT_NOT_DEBUGGING(format) print(format)


PRINT_IF_DEBUGGING("test"); // -> print("test");

#define DEBUG
PRINT_IF_DEBUGGING("test"); // -> debugPrint("test");
#undef DEBUG

PRINT_IF_DEBUGGING("test"); // -> print("test");

3. 注意事项

对此的一个小警告是,如果定义了DEBUG ,它必须扩展为有效的预处理标记(因此它必须只包含字母、数字和下划线)——否则连接将导致错误。

所以这行不通

#define DEBUG ()
#define DEBUG +

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM