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

跨平台C基礎框架實戰:從Makefile到多級日誌庫的完整構建

     編輯:關於C語言

項目目錄結構設計

sc_console/
├── Makefile              # 構建腳本
├── main/
│   └── main.c            # 業務入口與測試
└── module/
    └── schead/           # 核心基礎模塊
        ├── include/      # 對外頭文件
        │   ├── scatom.h  # 原子操作
        │   ├── schead.h  # 跨平台宏/工具
        │   └── sclog.h   # 多級日誌接口
        ├── schead.c      # 平台相關實現
        └── sclog.c       # 日誌核心實現

Makefile 關鍵技術點

CC=gcc
DEBUG=-g -Wall -D_DEBUG
PTHREAD=-lpthread
DIR=-I./module/schead/include

RUN=$(CC) $(DEBUG) -o $@ $^ $(PTHREAD) $(DIR)
RUNO=$(CC) $(DEBUG) -c -o $@ $^ $(DIR)

sc_console.out: main.o schead.o sclog.o
	$(RUN)

main.o: ./main/main.c
	$(RUNO)

schead.o: ./module/schead/schead.c
	$(RUNO)

sclog.o: ./module/schead/sclog.c
	$(RUNO)

clean:
	rm -rf *.i *.s *.o *.out __* log; ls -hl
  • `-g -Wall`:調試符號 + 全警告
  • `-D_DEBUG`:編譯期開啟調試宏,控制日誌級別輸出
  • 模式規則分離編譯(`.o`)與鏈接(`.out`),支持增量構建
  • `clean` 目標清理中間文件、日誌、持久化數據

核心模塊詳解

1. 原子操作抽象層

屏蔽 GCC `__sync_*` 與 MSVC `Interlocked*` 差異:

/* scatom.h 關鍵宏 */
#if defined(_MSC_VER)
#define ATOM_FETCH_ADD(v,a) InterlockedExchangeAdd((LONG*)&(v), (LONG)(a))
#define ATOM_LOCK(v) while(ATOM_SET(v,1)) Sleep(0)
#elif defined(__GNUC__)
#define ATOM_FETCH_ADD(v,a) __sync_fetch_and_add(&(v), (a))
#define ATOM_LOCK(v) while(ATOM_SET(v,1)) usleep(2)
#endif

提供:原子增減、設置、比較交換、自旋鎖。注意:MSVC 強轉 `LONG*` 因 API 要求 32 位操作數。

2. 跨平台基礎設施

  • 錯誤碼統一:`_RT_OK=0, _RT_EB=-1, _RT_EP=-2...`
  • 浮點比較:`EQ_FLOAT(x,y)` 容差判斷
  • 時間/睡眠:`SLEEPMS(ms)`、`gettimeofday()` Windows 移植、`localtime_r` 線程安全封裝
  • 大小端檢測:聯合體法 `sh_isbig()`
  • 安全內存釋放:`sh_free(void**)` 雙重指針置 NULL 防野指針
  • 掃描輸入健壯化:`SAFETY_SCANF` 清理緩衝區重試
  • 代碼計時:`TIME_PRINT(code_block)` 微秒級測量

3. 多級異步日誌庫

接口設計亮點

  • 線程私有上下文:`pthread_key_t` + `pthread_once_t` 管理 `logid`、`reqip`、`mod`、`timev`
  • 宏模板展開:`SL_FATAL(fmt,...) → sl_printf("[%s][FATAL][file:line:func][logid:%u][reqip:%s][mod:%s]" fmt)`
  • 雙文件分級:普通日誌 `sc.log`(全級別)、告警日誌 `sc.log.wf`(僅 FATAL/WARNING)
  • 持久化 logid:退出時寫入 `__lid__` 文件,重啟續號
  • 發布版裁剪:`_DEBUG` 控制 `SL_DEBUG/SL_TRACE` 編譯消除

核心實現流程

/* sclog.c 關鍵點 */
static pthread_key_t __lkey;
static pthread_once_t __lonce = PTHREAD_ONCE_INIT;
static unsigned __logid = 0;

int sl_pecific_init(const char* mod, const char* reqip) {
    pthread_once(&__lonce, __gkey);  // 單次創建 key
    struct slinfo* pl = pthread_getspecific(__lkey);
    if (!pl) pl = malloc(sizeof(*pl));  // 首次分配
    gettimeofday(&pl->timev, NULL);
    pl->logid = ATOM_ADD_FETCH(__logid, 1);  // 原子遞增唯一ID
    strcpy(pl->mod, mod);
    strcpy(pl->reqip, reqip);
    pthread_setspecific(__lkey, pl);
    return _RT_OK;
}

int sl_printf(const char* format, ...) {
    char tstr[64], logs[8192];
    sh_times(tstr, 63);  // 當前時間戳
    int len = snprintf(logs, sizeof(logs), "[%s ", tstr);
    va_list ap; va_start(ap, format);
    vsnprintf(logs+len, sizeof(logs)-len, format, ap);
    va_end(ap);
    fputs(logs, __slmain.log);  // fputs 線程安全
    if (format[4]=='F' || format[4]=='W')  // FATAL/WARNING
        fputs(logs, __slmain.wf);
    return _RT_OK;
}

Windows 移植要點

  • 引入 `pthread-w32`:配置頭文件目錄、庫目錄(`x86`/`x64`)、複製 `pthreadVC2.dll` 到輸出目錄
  • VS 項目屬性:`_CRT_SECURE_NO_WARNINGS`、運行庫 `MD/MDd`、調試信息 `/Zi`、優化 `/Od`
  • 修正 `pthread.h` 中 `timespec` 重定義衝突
  • Release 調試配置:生成 PDB、關閉優化、啟用鏈接器調試信息

運行效果驗證

Linux/Windows 雙平台編譯運行,生成結構化日誌:

[2017-01-21 10:17:33][FATAL][main.c:45:main][logid:1][reqip:0.0.0.0][mod:main thread] pthread test one fatal is at 0, It's OK.
[2017-01-21 10:17:33][WARNING][main.c:46:main][logid:1][reqip:0.0.0.0][mod:main thread] pthread test one warning is at 0, It's OK.

完美實現跨平台、多線程、分級、帶上下文的生產級日誌系統。

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