Создание функциональных макросов - PullRequest
1 голос
/ 29 января 2010

gcc 4.4.2 c89

У меня есть этот фрагмент кода, который я должен повторить во многих моих кодах. Мне просто интересно, есть ли способ сделать его коротким, используя функцию макроса?

Есть код, который я хотел бы изменить.

ERR_INFO error_info; /* create error object */
ErrorInfo(&error_info); /* pass the address for it to be filled with error info */
fprintf(stderr, "And the error is? [ %s ]\n", error_info.msg); /* display the error msg */

И моя попытка создать макрофункцию для ее использования.

#define DISPLAY_ERR(error_info) ErrorInfo(&error_info) error_info.msg
fprintf(stderr, "And the error is? [ %s ]\n", DISPLAY_ERR); /* display the error

Любые предложения будут наиболее полезны,

Ответы [ 4 ]

6 голосов
/ 29 января 2010

Если вы действительно хотите макрос:

#define DISPLAY_ERR(error_info) \
    do \
    { \
        ErrorInfo(&(error_info)); \
        fprintf(stderr, "And the error is? [ %s ]\n", (error_info).msg); \
    } while(0)

Вам нужен do... while(0) из-за веской причины .

Затем вы вызываете свой макрос, когда хотите напечатать ошибку:

if (error) {
    DISPLAY_ERR(error_info);
    /* more statements if needed */
}

Я предполагаю, что error_info был определен где-то. Если нет, или если вы не хотите, то вы можете изменить определение макроса и использовать:

#define DISPLAY_ERR() \
    do \
    { \
        ERR_INFO error_info;
        ErrorInfo(&error_info); \
        fprintf(stderr, "And the error is? [ %s ]\n", error_info.msg); \
    } while(0)

if (error) {
    DISPLAY_ERR();
    /* more statements if needed */
}
1 голос
/ 29 января 2010

Есть несколько способов сделать это. Вы можете использовать оператор запятой:

#define DISPLAY_ERR(error_info) (ErrorInfo(&(error_info)),(error_info).msg)

... или вы можете изменить функцию ErrorInfo() так, чтобы ее возвращаемое значение было указателем, по которому вы ее передаете:

#define DISPLAY_ERR(error_info) (ErrorInfo(&(error_info))->msg)

(и еще несколько опций).

1 голос
/ 29 января 2010

Вам нужно сделать так, чтобы он работал как вызов функции, поэтому его можно использовать везде, где возможен вызов функции, за исключением случаев, когда значение не возвращается. Вам также нужно пометить концы промежуточных строк обратной косой чертой. И идиома 'do { ... } while (0) полезна в этом контексте:

#define DISPLAY_ERR() do { ERR_INFO error_info; ErrorInfo(&error_info); \
     fprintf(stderr, "And the error is? [ %s ]\n", error_info.msg); } while (0)

Переменная error_info является локальной для блока, поэтому вам не нужно забывать объявлять ее в функциях, где вы используете макрос (или иметь его как статический файл или, как вы думаете, глобальную переменную) .

Обратите внимание, что этот код не возвращает значение, но его можно использовать в любом месте функции, где можно использовать выражение void:

if (somefunc() != 0)
    DISPLAY_ERR();
else if (anotherfunc() != 0)
    DISPLAY_ERR();
else
    do_something_useful_after_all();

1012 * Etc. *

Я все еще хотел бы убедиться, что я измерил издержки использования обычной функции по сравнению с наличием подобного функции макроса. При достаточно частом использовании вам, возможно, все-таки будет лучше с реальной функцией.

1 голос
/ 29 января 2010

Вы пытаетесь создать макрос, который "возвращает" значение? В C ++ вы можете использовать оператор запятой , для вычисления левого выражения, а затем вернуть правое выражение. Вы можете сделать то же самое в C тоже.

(foo(var), var.field) // foo(...)is evaluated first,
                      // then second expression is returned

также

DISPLAY(message) // Pass an argument to macro
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...