2009-11-16 69 views
1

gcc 4.4.1 C99定義函數宏

我寫了一個函數,用於向用戶顯示消息。這工作正常,我會需要它是可擴展的,因爲我將有更多的錯誤代碼以後添加。

但是,輸入將是優先級,error_code和錯誤的簡短說明。我已經包含了該功能和行號。

但是,我想將函數調用包裝成一個宏,但不知道該怎麼做呢?

任何人都可以指出我的寫作方向嗎?

非常感謝您的任何建議,

#include <stdio.h> 
#include <stdarg.h> 

typedef enum 
{ 
    ST_BIND_ERR = 1, 
    ST_SOCK_ERR, 
    ST_CONNECT_ERR, 
    ST_ACCEPT_ERR 
}error_codes; 

typedef enum 
{ 
    ST_CRITICAL = 1, 
    ST_WARNING, 
    ST_DEBUG, 
    ST_INFO 
}priority; 

#define REPORT(prio, err, msg) /* Defining macro here */ 

void report_msg(int prio, int err, const char *fmt, ...); 

int main(void) 
{ 
    printf("=== Starting program ===\n"); 

    report_msg(ST_WARNING, ST_CONNECT_ERR, "Error trying to make connection : FUNCTION [ %s ] : LINE [ %d ]", 
     __func__, __LINE__); 

    return 0; 
} 

void report_msg(int prio, int err, const char *fmt, ...) 
{ 
    va_list ap; 
    char priority_msg[512] = {0}; 
    char error_code[256] = {0}; 
    char format[256]  = {0}; 
    char output_msg[256] = {0}; 

    switch(prio) 
    { 
    case ST_CRITICAL: 
     sprintf(priority_msg, "[ ST_CRITICAL ]"); 
     break; 

    case ST_WARNING: 
     sprintf(priority_msg, "[ ST_WARNING ]"); 
     break; 

    case ST_DEBUG: 
     sprintf(priority_msg, "[ ST_DEBUG ]"); 
     break; 

    case ST_INFO: 
     sprintf(priority_msg, "[ ST_INFO ]"); 
     break; 

    default: 
     sprintf(priority_msg, "[ UNKNOWN_PRIO ]"); 
     break; 
    } 

    switch(err) 
    { 
    case ST_BIND_ERR: 
     sprintf(error_code, "[ ST_BIND_ERR ]"); 
     break; 

    case ST_SOCK_ERR: 
     sprintf(error_code, "[ ST_SOCK_ERR ]"); 
     break; 

    case ST_CONNECT_ERR: 
     sprintf(error_code, "[ ST_CONNECT_ERR ]"); 
     break; 

    case ST_ACCEPT_ERR: 
     sprintf(error_code, "[ ST_ACCEPT_ERR ]"); 
     break; 

    default: 
     sprintf(error_code, "[ UNKNOWN_ERR ]"); 
     break; 
    } 

    va_start(ap, fmt); 
    vsprintf(format, fmt, ap); 
    va_end(ap); 

    sprintf(output_msg,"%s %s %s", priority_msg, error_code, format); 

    fprintf(stderr, output_msg); 
} 

回答

1

調用者實際上是否需要可變數量的參數?例如,你是否希望他們能夠做到這樣的事情?

REPORT(ST_WARNING, ST_CONNECT_ERR, "Error trying to make connection : " 
    "FUNCTION [ %s ] : LINE [ %d ], target address [ %s]", target); 

我會這樣認爲的,因爲如果不是這樣,那麼根本就不需要可變參數。

所以,這個假設,我想我會首先做到這一點:

#define REPORT(prio, error, format, ...) report_msg(prio, error, format, __func__, __LINE__, __VA_ARGS__) 

,如果你這樣做,那麼你依靠呼叫者正確結合的功能和線進入錯誤信息。這對於來電者來說很麻煩。所以,其實我可能會更多的東西是這樣的:

#define REPORT(prio, error, format, ...) report_msg(prio, error, format, __func__, __LINE__, __VA_ARGS__) 

void report_msg(int prio, int err, const char *fmt, const char *func, int line, ...) { 
    // print the prio and error codes 
    // ... 

    // I've put some fprintf in here to avoid introducing even more buffers, 
    // but you can still do what you were doing before, building one big message. 
    fprintf("in function %s at line %d\n", func, line); 
    va_start(ap, fmt); 
    vsprintf(format, fmt, ap); 
    va_end(ap); 
    fprintf("\t%s\n", format); 
} 

然後調用程序如下:

REPORT(ST_WARNING, ST_CONNECT_ERROR, "target address [ %s ]", my_addr); 

和錯誤看起來是這樣的:

[ST_WARNING] [ST_CONNECT_ERROR] in function main at line 28 
    target address [ 69.59.196.211 ] 

最後一點:如果這些優先級和錯誤代碼僅適用於此功能,因此最好#將它們定義爲字符串,並將相應的參數更改爲const char*。這樣你就不需要switch語句,並且可以毫不費力地添加新代碼(或者調用者可以快速指定其他字符串,如果他們在調試時需要引人注目的話)。

即使它們必須是數字,您的交換機也會包含不必要的格式。你可以做這樣的事情:

char *priority_msg; 
switch(prio) { 
    case ST_WARNING: priority_msg = "[ ST_WARNING ]"; break; 
    // other cases... 
    default: priority_msg = "[ UNKNOWN_PRIO ]"; break; 
} 

或本:

char *priorities[] = {"[ UNKOWN_PRIO ]", "[ ST_ERROR ]", "[ ST_WARNING ]", ... }; 
char *priority_msg = priorities[0]; 
if (prio >= 0) && (prio < sizeof(priorities)/sizeof(*priorities)) { 
    priority_msg = priorities[prio]; 
} 

,你知道的重點是從1開始的連續編號這工作只要,只要你確保該枚舉和字符串保持同步。所以修改起來比開關語句要難一些,但海事組織更容易閱讀。

4

C99支持vararg macros,它似乎可以使用,使其多一點方便:

#define REPORT(prio, err, format, ...) report_msg(prio, err, format, __VA_ARGS__) 

這實際上並不顯得保存儘管如此,只是調用函數還有很多工作。也許你應該重新定義REPORT宏來包含優先級,或者什麼?

+0

你好,這是我第一次使用可變參數宏。什麼是重新設計的最佳方式? – ant2009 2009-11-16 15:15:51