簡體   English   中英

定義函數宏

[英]Defining function macros

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);
}

C99支持vararg宏 ,您似乎可以使用它來使其更加方便:

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

不過,這似乎並沒有比僅調用函數節省太多的工作。 也許您應該重新定義REPORT宏以包含優先級,還是其他?

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

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

我會這樣假設,因為如果不是這樣,則根本不需要varargs。

因此,基於這個假設,我想我首先要這樣做:

#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 ]

最后說明:如果這些優先級和錯誤代碼僅與此功能一起使用,則最好首先將它們#define定義為字符串,然后將相應的參數更改為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開始的連續數字,並且只要確保枚舉和字符串保持同步,此方法就起作用。 因此,與大的switch語句相比,修改起來有些困難,但是IMO則更易於閱讀。

暫無
暫無

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

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