Передача имени переменной в виде строки в функцию с параметрами по умолчанию - PullRequest
4 голосов
/ 02 апреля 2012

Допустим, есть функция отладки, которая здесь упрощена как:

void DumpString(char* var, char* varname) {
    printf("%s : '%s'\n", varname, var);
}

char str[10]="foobar";
DumpString(str, "str");

> str : foobar

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

#define VARASSTR(v) #v

void DumpString(char* var) {
    printf("%s : '%s'\n", VARASSTR(var), var);
}

char str[10]="foobar";
DumpString(str);

> var : foobar

Oops!Он использует имя локальной переменной вместо переданного внутрь. Давайте попробуем другой (и менее идеальный) метод:

#define DumpStr(v) DumpString(v, #v)

void DumpString(char* var, char* varname) {
    printf("%s : '%s'\n", varname, var);
}

char str[10]="foobar";
DumpStr(str);

> str : foobar

Отлично, это работает.Но что, если функция была немного более сложной:

void DumpString(char* var, char* varname, int optionalvar=0) {
    printf("%s : '%s'\n", varname, var);
    printf("blah: %d", optionalvar);
}

Перегрузить макрос невозможно, поэтому DumpStr не будет работать, и мы уже исключили версию с VARASSTR.

Как это можно сделать (не прибегая к множеству одинаково, но с разными именами функций / макросов)?

1 Ответ

1 голос
/ 02 апреля 2012

Это нестандартно, но работает как расширение в GNU C:

#define DumpStr(v, ...) DumpString(v, #v, ##__VA_ARGS__)

В GNU C вы не можете передавать аргументы в макрос с переменным числом, а «оператор вставки токена» ## при применении между запятой и пустым списком аргументов с переменным значением ничего не дает (поэтому запятая в конце заполняется). 1005 *

В Visual C ++, я считаю, что оператор вставки токена ## не нужен (и, вероятно, нарушит макрос), поскольку Visual C ++ автоматически подавляет завершающую запятую, если она появляется перед пустым списком аргументов переменной.

Обратите внимание, что единственное, что делает этот нестандартный, это желание иногда передавать пустой список аргументов. Макросы Variadic стандартизированы как в C99, так и в C ++ 11.


Редактировать: А вот пример, который не использует нестандартные функции. Вы можете понять, почему некоторые люди действительно очень хотят, чтобы в стандарте рассматривались такие вещи:

#define DUMPSTR_1(v) DumpString(v, #v)
#define DUMPSTR_2(v, opt) DumpString(v, #v, opt)
#define DUMPSTR_NARG(...) DUMPSTR_ARG_N(__VA_ARGS__, 4, 3, 2, 1, 0)
#define DUMPSTR_ARG_N(_1, _2, _3, _4, n, ...) n
#define DUMPSTR_NC(f, ...) f(__VA_ARGS__)
#define DUMPSTR_NB(nargs, ...) DUMPSTR_NC(DUMPSTR_ ## nargs, __VA_ARGS__)
#define DUMPSTR_NA(nargs, ...) DUMPSTR_NB(nargs, __VA_ARGS__)
#define DumpStr(...) DUMPSTR_NA(DUMPSTR_NARG(__VA_ARGS__), __VA_ARGS__)

Вероятно, есть несколько более чистых способов сделать это. Но не так много.


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

#define STRINGIFY_IMPL(s) #s
#define STRINGIFY(s) STRINGIFY_IMPL(s)
#define ARG1_IMPL(a, ...) a
#define ARG1(...) ARG1_IMPL(__VA_ARGS__, 0)
#define DumpStr(...) DumpString(STRINGIFY(ARG1(__VA_ARGS__)), __VA_ARGS__)

Обратите внимание, что для этого требуется изменить порядок аргументов DumpString так, чтобы строковое имя функции было первым аргументом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...