2012-05-21 2 views
10

Следующий код C++ компилируется и работает программистом, предназначенного на GCC (4.0.4)препроцессора макросы в качестве параметров других макросов

#define FOO(x,y,z) ((x)*(y)*(z)) 
#define BAR(x) FOO(x,1) 
#define BAZ 3,7 

int main() 
{ 
    return BAR(BAZ); /* interpreted as return ((3)*(7)*(1)); */ 
} 

Однако макросы вызывают ошибку на Microsoft Visual C++ Express 2010:

main.cpp (7): предупреждение C4003: не хватает фактических параметров для макроса 'Foo'
main.cpp (7): ошибка C2059: синтаксическая ошибка: ')'

Проблема заключается в том, что компилятор Microsoft при обработке макроса BAR внутренне не расширяет макрос BAZ до параметров, которые могут использоваться как два отдельных параметра для макроса FOO.

В соответствии со стандартом, который компилятор правильно обрабатывает ситуацию?

+0

Кажется, что вы действительно ищете [variadic macros] (http://en.wikipedia.org/wiki/Variadic_macro). – leftaroundabout

+3

@leftaroundabout это не похоже, что он ... –

+3

@iammilind: Что отсутствует в главе 16 стандарта? Как это не «настоящий» стандарт? –

ответ

12

Согласно 16.3.4 ИСО/МЭК 14882: 2003 (C++ Stardard) макроподстановки выполняется следующим образом:

  1. Macro вызов заменяется списком замены макроса (тела), где каждое имя параметра (если только это не влияет на # или ##) заменяется полным расширением макроса соответствующего аргумента, указанного в вызове макроса.
  2. Результат этапа 1: rescanned. Если в нем больше макросов (кроме тех, которые уже были расширены с учетом рассматриваемого текста), они расширяются в соответствии с той же процедурой рекурсивно.

Последовательность шагов для кода Указан:

  1. BAR(BAZ)
  2. FOO(3,7,1)
  3. ((3)*(7)*(1))

Так GCC является правильным, и VC не является. Но ошибка, о которой жалуется VC, заключается в том, что FOO имеет 3 аргумента, а BAR указывает только 2 из них. VC, по-видимому, пытается поймать ошибки как можно скорее и идет слишком далеко.

+1

Я не понимаю, как алгоритм, который вы дали, соответствует поведению GCC. Если я прочитал его правильно, алгоритм будет выглядеть следующим образом: 'BAR (BAZ)' является вызовом 'BAR' с аргументом' BAZ', поэтому его заменяет 'FOO (BAZ, 1)'. Теперь это происходит повторно. Первый макрос, который он находит, это 'FOO', поэтому теперь он пытается развернуть' FOO' с аргументами 'BAZ' и' 1'. Недостаточно аргументов, поэтому препроцессинг терпит неудачу. Почему повторное сканирование 'FOO (BAZ, 1)' сначала расшифровывает 'BAZ', когда сканирование' BAR (BAZ) 'сначала расширяет' BAR'? – Mankarse

+0

@Mankarse Спасибо, это действительно было недостаточно ясно. Исправлена. –

+0

Спасибо за четкое и полное объяснение. Я многому научился. – Mankarse