2014-01-31 6 views
5

Как можно определить С макро IFARGS(YES, NO, ...) таким образом, что применение IFARGS без дополнительных аргументов производит NO и применение IFARGS с одним или несколькими аргументами производит YES?обнаружить наличие или отсутствие аргументов в C макрос

У меня есть ответ с использованием GCC (см. Ниже), но я предпочел бы один для C99, если это возможно (или доказательство его невозможности).

ответ

1
#define GET(_0, _1) _0 // Return the first of two arguments 
#define GET_(_0, _1) _1 // Return the second of two arguments 

#define JOIN(_0, _1) _0 ## _1 // Concatenate two arguments 
#define EJOIN(_0, _1) JOIN(_0, _1) // Expand macros and concatenate 

#define FIRST(_, ...) _ // Truncate everything after first comma 
#define EFIRST(_) FIRST(_) // Expand argument and pass to FIRST 

#define REST(_0, ...) __VA_ARGS__ // Remove everything before first comma 

#define GET_GET(...) \ 
    EJOIN(GET, EFIRST(REST(,,##__VA_ARGS__ _))) // Branch between GET and GET_ 

#define IFARGS(YES, NO, ...) GET_GET(__VA_ARGS__)(YES, NO) 

Обратите внимание, что если бы это было возможно в C99, то можно было бы смоделировать ##__VA_ARGS__, например, так:

#define PREPEND_COMMA(...) , __VA_ARGS__ 
#define NO_COMMA() 
#define PREPEND_COMMA_IF_NONEMPTY(...) IFARGS(PREPEND_COMMA, NO_COMMA, __VA_ARGS__)(__VA_ARGS__) 

Тогда любой экземпляр , ##__VA_ARGS__ может быть заменен PREPEND_COMMA_IF_NONEMPTY(__VA_ARGS__).

+0

Это не ответ, а просто дополнение к вашему собственному вопросу. –

+0

@JensGustedt Первое поле кода является частичным решением - оно имеет желаемое поведение, но требует '## __ VA_ARGS__', которое является расширением GCC для синтаксиса макроса C99. – augurar

+0

Я это заметил. Немногие исследования по SO могли бы показать вам ответ на этот вопрос. См. Ссылку выше. –

4

В C99 можно определить, является ли аргумент макроса пустым, но делает это устойчивым против всех коэффициентов, которые могут появиться в этом аргументе (аргументы, которые сами расширяются, содержат () и тому подобное). Мой пакет макросов P99 реализует такую ​​вещь, поэтому вам не придется слишком беспокоиться. При этом ваш макрос может быть реализован как

#define IFARGS(YES, NO, ...) P99_IF_EMPTY(__VA_ARGS__)(YES(__VA__ARGS__))(NO()) 

Как видно из названия, P99 имеет только функции C99 для этого.

+0

Как можно обнаружить пустой аргумент в C99? – augurar

+0

@augurar, этот находится в верхнем поиске на моем любимом поисковом сервере :) http://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ –

+0

Интересно; однако макрос «ISEMPTY» в этом сообщении, похоже, терпит неудачу, если ему задано ровно 16 аргументов. – augurar