Variadic Macro вызывает fprintf: как добавить аргументы в __VA_ARGS__? - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть два макроса:

 #define LogFunction(str)       fprintf(stdout, "%s: %s\n",__FUNCTION__,(str))
 #define LogPrintf(f_, ...)     fprintf(stdout, (f_), ##__VA_ARGS__)

Так что я могу использовать их следующим образом:

void MyFunction()
{
    int N=4;
    LogFunction("START");      // Outputs "MyFunction: START"
    LogPrintf("N=%d\n", N);    // Outputs "N=4"
}

То, что я хотел бы изменить, на

  1. добавьте FUNCTION в начале LogPrintf, как в LogFunction
  2. добавьте "\ n" в конце LogPrintf, не забывая вставлять его в себя

так что в итоге у меня мог быть только один макрос для моих выходных данных.

Я пытался понять, мог ли Присоединение к __VA_ARGS __ быть полезным, но я признаючто я не понял, связано ли это с моим делом: (

Спасибо.

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

Если вы хотите положиться на первый аргумент, чтобы LogPrintf был строковым литералом, тогда вы должны использовать конкатенацию строк для достижения своей цели:

// Assumes f_ always corresponds to a string literal:
#define LogPrintf(f_, ...)    fprintf(stdout, "%s: " f_ "\n", __FUNCTION__, ##__VA_ARGS__)

Обратите внимание, однако,что в стандартном C макрос LogPrintf требует как минимум двух аргументов, а ## не имеет места.Я держу его здесь только потому, что вы используете его в своем исходном коде.

Однако если вы должны принимать строковые выражения формата, отличные от строковых литералов, тогда ваша самая простая альтернатива - выполнить несколько вызовов ввода-вывода в качестве другого ответа.также предлагает:

#define LogPrintf(f_, ...)    do {         \
    fprintf(stdout, "%s: ", __FUNCTION__); \
    fprintf(stdout, (f_), ##__VA_ARGS__);  \
    fputc('\n', stdout);                   \
} while (0)

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

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

#define LogPrintf(f_, ...)    log_printf_impl(stdout, __FUNCTION__, (f_), ##__VA_ARGS__)

int log_printf_impl(FILE *f, const char *func, const char *fmt, ...) {
    static const char prefix[] = "%s: ";
    size_t flen = strlen(fmt);
    va_list args;
    int result = -1;
    char *aug_fmt = malloc(sizeof(prefix) + strlen(fmt) + 1);

    if (aug_fmt) {
        va_start(args, fmt);
        sprintf(aug_fmt, "%s%s\n", prefix, fmt);
        result = vfprintf(f, aug_fmt, func, args);
        va_end(args);
        free(aug_fmt);
    }

    return result;
}
0 голосов
/ 28 ноября 2018

почему бы не сделать это в 3 шага?

#define LogPrintf(f_, ...)   do { fprintf(stdout, "%s: ",__FUNCTION__); \
                                  fprintf(stdout, (f_), ##__VA_ARGS__); \
                                  fprintf(stdout,"\n"); } while(0)

это делает 3 отпечатка, но, по крайней мере, это просто и делает то, что вы хотите.трюк do while(0) гарантирует, что это единственный блок (при использовании if без фигурных скобок) и требует точки с запятой.

...