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

C 宏進階:# 字串化運算符與逗號表達式的妙用

     編輯:關於C語言

# 運算符:將宏參數「字串化」

在宏定義中,# 置於參數前,會將該參數的原始語彙轉換為字串常值(雙引號包裹)。這在除錯追蹤、日誌輸出極為實用。

基本規則

  • 僅能用於宏定義內部,不可在普通語句中使用。
  • 參數經過宏展開後,再被 # 字串化(若參數本身是宏,會先展開)。
  • 字串化結果自動加上雙引號,並轉義內部引號與反斜線。

經典範例:TRACE 宏

#define TRACE(S) (printf("%s\n", #S), S)  // 逗號表達式:先印字串,再返回 S 的值

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    int a = 5;
    int b = TRACE(a);           // 輸出 "a",b = 5
    const char *str = "hello";
    char des[50];
    strcpy(des, TRACE(str));    // 輸出 "str",des = "hello"
    puts(des);
    system("pause");
    return 0;
}

輸出結果:

a
str
hello

深度解析:為什麼 strcpy(des, TRACE(str)) 能複製字串內容?

  1. TRACE(str) 展開為 (printf("%s\n", "str"), str)。
  2. 逗號表達式左邊先執行(印出 "str"),整個表達式的值為右邊最後一項,即 str(指標值)。
  3. strcpy 接收到的是 str 的指標,正常複製字串內容。

注意區分:int a = printf("%s\n", "S"); 中 a 是 printf 的返回值(印出字元數),而非字串 "S"。

## 連接運算符(補充)

雖未在原文提及,但常與 # 配合使用:## 可將兩個語彙連接成單一語彙(如生成變數名、函數名)。

#define CONCAT(a, b) a ## b
int CONCAT(var, 123) = 10; // 展開為 int var123 = 10;

實戰技巧:編譯期斷言與除錯宏

// 字串化檔名、行號、運算式
#define ASSERT(expr) \
    do { \
        if (!(expr)) { \
            fprintf(stderr, "Assertion failed: %s, file %s, line %d\n", #expr, __FILE__, __LINE__); \
            abort(); \
        } \
    } while(0)

// 變數名與值同印
#define LOG_VAR(x) printf("%s = %d\n", #x, x)

int count = 42;
LOG_VAR(count); // 輸出: count = 42

避坑指南

誤區正確理解
以為 #S 會展開 S 的值只字串化「語彙本身」,不計算值。TRACE(a+b) 印出 "a+b" 而非 "15"
在宏外使用 #編譯錯誤,# 只在宏替換列表中有效
忽略逗號表達式求值順序左邊為副作用(如印字),右邊為整體表達式的值

善用 # 與逗號表達式,能寫出既高效又具自我描述能力的除錯宏,是 C 語言元程式設計的基礎利器。

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