2015-09-23 5 views
2

Например я хочу написать свои собственные Е() вариант, но я должен выполнять расчеты по переменным аргументам:Как расширить макрос и удалить запятую

#define log(fmt_string, ...) my_log(fmt_string, pack_args(__VA_ARGS__), __VA_ARGS__) 

где pack_args (...) - это макрос тоже. Как мне изменить этот код для обработки только сценария присутствия fmt_string?

log("Some message here"); 
+0

Непосредственно, связанный с вашим вопросом, но этот макрос будет обрабатывать аргументы дважды. например, «log (« foo% d », func());' вызовет func дважды. Чтобы исправить это, вы можете сделать функцию, например. 'my_log_pack (char const *, ...);' который обрабатывает свой список параметров дважды. –

ответ

3

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

#define P00_ARG(            \ 
_1, _2, _3, _4, _5, _6, _7, _8,        \ 
_9, _10, _11, _12, _13, _14, _15, _16,      \ 
    ... etc ...             \ 
_153, _154, _155, _156, _157, _158, _159,      \ 
...) _159 
#define P99_HAS_COMMA(...) P00_ARG(__VA_ARGS__,    \ 
1, 1, 1, 1, 1, 1, 1,           \ 
1, 1, 1, 1, 1, 1, 1, 1,          \ 
    ... etc ....             \ 
1, 1, 1, 1, 1, 1, 0, 0) 

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

#define log(...) log2(P99_HAS_COMMA(__VA_ARGS__), __VA_ARGS__) 
#define log2(N, ...) log3(N, __VA_ARGS__) 
#define log3(N, ...) log ## N(__VA_ARGS__) 

#define log0(FMT)    /* your version with format only goes here */ 
#define log1(FMT, __VA_ARGS__) /* your version with more goes here */ 
1

Как я должен изменить этот код [ручки] единственный сценарий присутствия fmt_string?

Вы не можете сделать это на все с VARIADIC макро в стандартном C. Стандарт явно указывает, что в вызове в VARIADIC макро «там будет больше аргументов в вызове, чем есть параметры в определении макроса (исключая ...) »(C2011, 6.10.3/4). Вы можете разрешить макрос для использования только с одним аргументом, изменив его ...

#define log(...) /* ... */ 

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

Если вам необходимо поддерживать список аргументов переменной нулевой длины, вам нужно использовать функцию bona fide.

+0

gcc фактически ** может ** удалить ведущую запятую для '__VA_ARGS__'. IIRC просто префикс с '##' (лучше проверить в документации) в качестве расширения. – Olaf

+1

@Olaf, вы правы, что * в качестве расширений *, GCC позволяет вызывать переменный макрос с нулевыми переменными аргументами и обрабатывает оператор '##', который появляется между запятой и '__VA_ARGS__', подавляя запятую. Возможно, это послужит OP, но я редко склонен рекомендовать включать зависимости от поведения, характерного для конкретного компилятора. –

+0

Ну, я немного раскололся. В общем, мне не нравится полагаться на функции компилятора. OTOH, я вижу gcc как OSS и (один из) наиболее используемых компиляторов - какое-то исключение (я мог бы включить clang/llvm, если бы я знал их лучше). Это связано с тем, что вы не зависите от конкретного поставщика, но можете его сами портировать, если это необходимо. Также неожиданно внезапно исчезнет verrrrry. Во всяком случае, я думаю, мы должны оставить разрешение на ОП, просто предоставив информацию. Разве это не свобода? – Olaf