簡體   English   中英

我應該如何連接C中的宏?

[英]how should I concatenate macros in C?

我正在嘗試創建日志助手,並希望將行號連接到日志信息。

我想完成一個這樣的日志:(“ -l:” + LINE + args)

05-22 15:04:16.626 21270-22699/com.mydomain.myproject D/myfile.c: -l:5 myloginfo ...

這是我的loghelper.h文件中的內容:

#ifdef __ANDROID__
#include <android/log.h>
#define FILETAG (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1  : __FILE__)
#define LINEIDENTIFIER ' -l:'
#define TOKENAPPEND(x, y, z) x##y##z
#define APPENDLINE(x, y, z) TOKENAPPEND(x, y, z)
#define printf(fmt,args...)  __android_log_print(ANDROID_LOG_DEBUG, FILETAG , fmt, APPENDLINE(LINEIDENTIFIER, __LINE__, ##args))
#define printfe(fmt,args...)  __android_log_print(ANDROID_LOG_ERROR, FILETAG, fmt, APPENDLINE(LINEIDENTIFIER, __LINE__, ##args))
#define printfw(fmt,args...)  __android_log_print(ANDROID_LOG_WARN, FILETAG, fmt, APPENDLINE(LINEIDENTIFIER, __LINE__, ##args))
#endif

myfile.c像這樣調用:

#include "loghelper.h"

...

printf(" myloginfo %s", "...");

我收到以下錯誤:

error: pasting formed '' -l:'52', an invalid preprocessing token
error: expected ')'
error: too many arguments provided to function-like macro invocation
error: use of undeclared identifier 'APPENDLINE'
error: pasting formed '57"success!"', an invalid preprocessing token
error: expected ')'

問:我在做什么錯? 我應該更改使其工作嗎?

您嘗試在無法使用令牌粘貼運算符##地方使用它。 令牌粘貼可用於創建新令牌,通常是新標識符:

#define MY(X) my_##X     // MY(func) -> my_func

在這里,您想連接字符串文字。 這里有兩件事要注意:

  • 您不需要預處理程序來連接字符串文字。 C語法將連接相鄰的字符串文字: "to" "gether"將被視為"together"
  • __LINE__宏擴展為整數,因此必須將其轉換為字符串文字。 字符串化運算符#不適用於特殊令牌__LINE__ ,因此您必須編寫宏以進行字符串化。 如果這樣做,則會得到字符串文字"__LINE__" ,它不是很有用。 使用double stringizing ,即再增加一層間接訪問,以獲取實際的行mumber作為字符串。

將所有這些付諸實踐,一個簡單的日志記錄宏可能看起來像這樣:

#define M_STR_(x) #x
#define M_STR(x) M_STR_(x)

#define LOG(...) fprintf(stderr, "Line " M_STR(__LINE__) ": " __VA_ARGS__)

為了簡單起見,我在這里使用了一個較短的示例。 需要注意的是:

  • 我在這里使用了標准的...__VA_ARGS__表示法,並且沒有在宏參數列表中拆分格式字符串和參數。 這樣,該宏將在不打印參數的情況下工作,並且您不需要非標准的##__VA_ARGS__即可抑制單個逗號。
  • 該宏僅在格式字符串應該是字符串文字時才起作用。 格式字符串"%s"將擴展為"Line " "12" ": " "%s"
  • 在格式字符串前面添加字符串文字很容易,但是在字符串字符串后面附加更復雜,例如,如果要用新行結束格式字符串。 您可以使用您的方法將fmt與args分開,但是堅持使用簡單的方法並使宏擴展為兩個打印語句可能更容易:一個用於格式化字符串,另一個用於換行。 (但是請確保將其包裝起來 ,以使這兩個命令不能分開。)

最后,該方法適用於您的printf重新安裝:

#define printf(...)                                       \
    __android_log_print(ANDROID_LOG_DEBUG, FILETAG,       \
    "-l " M_STR(__LINE__) ": " __VA_ARGS__)

這是基於@M Oehm答案的最終工作代碼,如果您想知道它是如何結束的。

#ifdef __ANDROID__
#include <android/log.h>
#define FILETAG (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1  : __FILE__)
#define GETLINE_(x) #x
#define GETLINE(x) GETLINE_(x)
#define printf(...)  __android_log_print(ANDROID_LOG_DEBUG, FILETAG , "-l" GETLINE(__LINE__) ": " __VA_ARGS__)
#define printfe(...)  __android_log_print(ANDROID_LOG_ERROR, FILETAG,  "-l" GETLINE(__LINE__) ": " __VA_ARGS__)
#define printfw(...)  __android_log_print(ANDROID_LOG_WARN, FILETAG, "-l" GETLINE(__LINE__) ": " __VA_ARGS__)
#endif

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM