簡體   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