首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

C/C++ 宏技巧:將符號自動轉換為字串 (# 號運算子)

     編輯:VC 教學

前言

在 C/C++ 前處理器中,# 號運算子(Stringizing Operator)是一個鮮為人知但極其實用的功能:它能將宏參數「原封不動」地轉換為字串常值。這在除錯訊息、日誌記錄、序列化等場合極為方便,能避免重複輸入字串字面值導致的維護困擾。

基本語法與運作原理

#define SymbolToString(s) #s

當呼叫 SymbolToString(ANY_TOKEN) 時,前處理器會將 ANY_TOKEN 替換為 "ANY_TOKEN"(含雙引號)。注意:

  • 參數內的空白字元會被壓縮為單一空格。
  • 參數若包含字串常值,其引號會被保留並加上跳脫字元。
  • 此運算子僅能用於宏參數,不可直接對變數或運算式使用。

實戰範例:Enum 值自動轉字串

傳統寫法需手寫 switch-case 對應每個列舉值,易出錯且難維護。善用 # 運算子即可一勞永逸:

#define EnumToStr(e) #e

enum Value { ONE, TWO, THREE };

void LogValue(Value v)
{
    switch (v)
    {
    case ONE:   std::cout << EnumToStr(ONE)   << std::endl; break;
    case TWO:   std::cout << EnumToStr(TWO)   << std::endl; break;
    case THREE: std::cout << EnumToStr(THREE) << std::endl; break;
    }
}
// 輸出: ONE / TWO / THREE (不含引號)

進階應用:除錯巨集與函式名稱記錄

結合 __FUNCTION__ (C99/C++11) 或 __FUNCSIG__ (MSVC),可建立強大的除錯巨集:

#define SymbolToStr(s) #s

// 除錯輸出巨集:自動包含檔案、行號、函式名、變數名與值
#define DEBUG_LOG_VAR(var) \
    OutputDebugStringA( \
        (std::string(__FILE__) + ":" + std::to_string(__LINE__) + " " \
         + __FUNCTION__ + " " + SymbolToStr(var) + " = " \
         + std::to_string(var) + "\n").c_str() )

// 使用範例
void ProcessData(int count, double ratio)
{
    DEBUG_LOG_VAR(count);  // 輸出: source.cpp:42 ProcessData count = 10
    DEBUG_LOG_VAR(ratio);  // 輸出: source.cpp:43 ProcessData ratio = 1.5
}

進階技巧:雙層巨集實現「參數展開後再字串化」

若宏參數本身也是巨集,需透過雙層巨集強制先展開再字串化:


#define _STR(s) #s
#define STR(s) _STR(s)

#define VERSION 1.2.3
const char* version_str = STR(VERSION); // 結果: "1.2.3" 而非 "VERSION"

應用場景總結

場景範例優勢
Enum/常數除錯輸出case ERR_OK: log(#ERR_OK);修改列舉值自動同步字串,零維護成本
單元測試斷言訊息ASSERT_MSG(cond, #cond)失敗時直接顯示條件運算式原文
序列化/反射標籤REGISTER_FIELD(name)欄位名稱與程式碼同步,避免字串硬編碼
自動產生字串對照表#define MAP_ENTRY(k) {k, #k}一次定義,編譯期生成查找表

注意事項與限制

  1. 無法用於執行期變數:#var 僅在前處理階段對宏參數生效。
  2. 參數副作用:若參數含有函式呼叫 #func(),不會執行函式,僅產生字串 "func()"。
  3. 字串化後不可再參與運算:結果為字串常值,屬於編譯期產物。

結語

善用 # 字串化運算子,能大幅減少重複字串字面值的撰寫,提升程式碼可維護性與除錯效率。配合 ## (Token Pasting) 與可變參數巨集 (C99 __VA_ARGS__),更能構建領域專用的元程式工具。下次撰寫 switch-case 對應列舉字串時,不妨嘗試這個小技巧,體會「一次定義,處處生效」的爽快感。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved