va_list 傳遞的繁瑣與不安全標準 printf 族函數內部處理變參簡單,但封裝二次開發時極其麻煩:
void Func(char* szFormat, ...) {
char szBuf[256];
// 錯誤!... 不能直接轉發
SafePrintf(szBuf, 256, ...); // 編譯失敗
}
ANSI C99 要求用 va_copy 複製 va_list,再 va_end 釋放,代碼冗長且易出錯。舊庫只能在每個變參函數開頭複製粘貼處理邏輯,違反 **「同樣邏輯只寫一次」** 原則。
TONY_FORMAT利用宏的文本替換特性,將變參展開、格式化、邊界檢查、結束符填充**固化為單一調用點**,調用者像調用普通函數一樣傳入格式串:
// 核心宏:4 參數 —— 輸出長度引用、緩衝區、緩衝區大小、格式串
#define TONY_FORMAT(nPrintLength, szBuf, nBufferSize, szFormat) \
{ \
va_list pArgList; \
va_start(pArgList, szFormat); \
nPrintLength += Linux_Win_vsnprintf(szBuf + nPrintLength, \
nBufferSize - nPrintLength, szFormat, pArgList); \
va_end(pArgList); \
if (nPrintLength > (nBufferSize - 1)) nPrintLength = nBufferSize - 1; \
*(szBuf + nPrintLength) = '\0'; \
}
// 基礎安全格式化函數
inline int SafePrintf(char* szBuf, int nBufSize, char* szFormat, ...) {
if (!szBuf || !nBufSize || !szFormat) return 0;
int nRet = 0;
TONY_FORMAT(nRet, szBuf, nBufSize, szFormat);
return nRet;
}
關鍵優勢:
nBufferSize 參數,杜絕緩衝區溢出Linux_Win_vsnprintf 宏映射 _vsnprintf/vsnprintf#define TONY_FORMAT_WITH_TIMESTAMP(nPrintLength, szBuf, nBufferSize, szFormat) \
{ \
time_t t; struct tm *pTM = NULL; \
time(&t); pTM = localtime(&t); \
nPrintLength += SafePrintf(szBuf, nBufferSize, "[%s", asctime(pTM)); \
szBuf[nPrintLength - 1] = '\0'; nPrintLength--; // 吃掉 asctime 自帶換行 \
nPrintLength += SafePrintf(szBuf + nPrintLength, nBufferSize - nPrintLength, "] "); \
TONY_FORMAT(nPrintLength, szBuf, nBufferSize, szFormat); \
}
inline int SafePrintfWithTimestamp(char* szBuf, int nBufSize, char* szFormat, ...) {
if (!szBuf || !nBufSize || !szFormat) return 0;
int nRet = 0;
TONY_FORMAT_WITH_TIMESTAMP(nRet, szBuf, nBufSize, szFormat);
return nRet;
}
TonyPrintf/TonyFPrintf統一入口,支持控制台/文件、帶/不帶時間戳:
#define TONY_LINE_MAX 1024
inline int TonyPrintf(bool bWithTimestamp, char* szFormat, ...) {
if (!szFormat) return 0;
char szBuf[TONY_LINE_MAX];
int nLen = 0;
if (!bWithTimestamp) { TONY_FORMAT(nLen, szBuf, TONY_LINE_MAX, szFormat); }
else { TONY_FORMAT_WITH_TIMESTAMP(nLen, szBuf, TONY_LINE_MAX, szFormat); }
return printf("%s", szBuf);
}
inline int TonyFPrintf(FILE* fp, bool bWithTimestamp, char* szFormat, ...) {
if (!fp || !szFormat) return 0;
char szBuf[TONY_LINE_MAX];
int nLen = 0;
if (!bWithTimestamp) { TONY_FORMAT(nLen, szBuf, TONY_LINE_MAX, szFormat); }
else { TONY_FORMAT_WITH_TIMESTAMP(nLen, szBuf, TONY_LINE_MAX, szFormat); }
return fprintf(fp, "%s", szBuf);
}
// 控制台輸出
[65]: 123.46, A, 0x00AABBCC
...
[Wed May 12 09:17:43 2010] [65]: 123.46, A, 0x00AABBCC
...
// 文件 test.txt 內容一致
多線程環境下,所有函數僅操作棧上私有緩衝區,**天然線程安全**,無需額外鎖。
CTonyMean 增量平均值模組(支持正負數混合、溢出自愈),已用於高精度計時器自適應修正函數型宏在「內聯優化」與「代碼復用」之間找到平衡點,解決了 C 語言變參二次封裝的長期痛點。配合嚴格邊界檢查、跨平台宏、時間戳擴展、雙輸出通道,構建出一套**工業級、零開銷、極易用**的格式化基礎設施。**把自己站在用戶立場,把 API 調整到自己用起來都「爽」**,這才是好庫的誕生之道。