2012-04-02 4 views
4

Допустим, есть функция отладки, упрощена здесь:Передача имя переменной в виде строки для работы с параметрами по умолчанию

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 

Упс! Он использует локальное переменное имя вместо одного передается в Попытаются другая (и менее идеальная) липкость:.

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

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

+0

«Как это можно обрабатывать (не прибегая к нескольким аналогичным, но по-разному названным функциям/макросам)?» Это невозможно. Вы не можете перегружать макросы. – meagar

+0

Вы должны попробовать некоторый язык с возможностями отражения. Нет, действительно. – iehrlich

+1

Вы можете использовать [Матричный трюк Variadic] (http: // stackoverflow.com/questions/5365440/variadic-macro-trick), чтобы «имитировать» перегрузку с помощью макросов. –

ответ

1

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

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

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

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

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


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

#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__) 

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


Edit 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 быть изменен так что строковое имя функции является первым аргументом.

+0

Есть решения этой проблемы без таких нестандартных хаков. –

+1

В частности, вы включаете весь список аргументов в '...', а затем используете макросы, которые извлекают первый аргумент (или любой другой аргумент) из '__VA_ARGS__'. –

+0

@R .. Да, есть. И * вау * это ужасно. Я добавил автономный способ, которым я барабанил. Можете ли вы предложить лучшую? –