2014-12-03 6 views
2

В самой простой программе C ниже, какова ожидаемая ошибка компилятора? НКУ дает мне 1, тогда как MSVC 2013 дает мне 2.Какое значение следует ожидать от макроса, установленного в результате определения()?

#define foo 
#define bar (defined(foo)) 

#if bar 
#error 1 
#else 
#error 2 
#endif 

Мои вопросы, надеюсь, столь же просто:

  1. Что делает C спецификации говорят о значении определенного()? Я не могу представить , чтобы найти что-нибудь, что говорит о настройке его значения на другой макрос .
  2. Фактический код не является чем-то, что у меня есть, и «#if bar» используется повсюду. Каков самый простой способ изменить #define, чтобы #if-бар работал как «ожидаемый» в MSVC? Единственное, что я могу придумать, это расширить его:

.

#ifdef foo 
#define bar 1 
#else 
#define bar 2 
#endif 
+0

Я сам тестировал это, это bizzare. Я не могу себе представить, что думает MSVC, что он здесь делает. –

ответ

2

: C спецификация говорит:

§6.10.1/1 Выражение ... может содержать унарный оператор выражения вида defined identifier или defined(identifier), которые вычисляются в 1, если идентификатор в настоящее время определяется в качестве имени макроса (то есть, если он предопределен или если он был предметом предпродажной директивы #define без промежуточной директивы #undef с тем же идентификатором субъекта), 0, если это не так.

§6.10.1/4 макро вызовов в списке предобработки лексем, которые станут контролирующего константного выражения заменяются (за исключением тех имен макросов, кроме модифицированного по унарному defined), так же, как в обычном тексте. Если маркер является defined генерируется в результате этого процесса замены или использование defined одноместный операции не соответствует одному из двух указанных форм до макро замены, поведения не определены . После того, как все замены из-за макрорасширения и оператор defined унарный были выполнены, все остальные идентификаторы (включая лексически , идентичные ключевым словам) заменяются номером pp 0, а затем каждый токен предварительной обработки преобразуется в токен.

(курсив мой) Однако, как макро замена является очень сложным, и я думаю, что MSVC является определяющим foo, как defined(bar), который не определено поведение, GCC является Тогда как определение foo как 1 правильно. Так как MSVC тогда в неопределенном поведении, он делает странные вещи.

Как вы говорите, проще исправить это

#ifdef foo 
#define bar 1 
#else 
#define bar 2 
#endif 
+1

Я не думаю, что что-то не так с тем, что делает MSVC. В этом случае * токен 'defined' генерируется в результате ... процесса замены *. В спецификации четко сказано, что это UB, поэтому поставщик реализации может выбирать любой курс действий. Компилятор может даже включать обе ветви условного фрагмента, и это будет законным источником удовольствия. – ach

+0

@ Андрей Черняховский: Я также заключил UB, но, перечитывая, мои рассуждения были неправильными; ты прав. –

+0

Я слишком скоро перестал читать спецификацию. Я понял, что это UB, но хотел убедиться. Спасибо за помощь! –

0

Я считаю, что компилятор будет видеть все после имени/макро определяется как часть определения имени/макро, то есть, как текст программы , а не как макротекст.

int defined(char s); // prototype of a function named "defined" 

#define foo 
#define bar defined(foo) 

«бар» в любом месте в тексте программы теперь будет заменен вызовом определенного() без аргументов (как «Foo» определяется как пустой).

+0

'defined' - это функция препроцессора магии> Любая функция C/C++ с тем же именем, вероятно, игнорируется. (Если такое поведение может быть неопределенным, мне нужно будет проверить) –

+0

@MooingDuck, почему вы так думаете? 'defined' определяется только определенным значением в условном выражении' # if' и '# elif'. В противном случае вполне законно иметь «определенный» в качестве идентификатора. – ach

+0

Я подтвердил, что 'defined' не является ключевым словом, поэтому да, это только определено, чтобы иметь особое значение в' if' и 'elif', в которых контексты, любая функция C/C++ с тем же именем, по-видимому, игнорируются. (Я vageuly задаюсь вопросом, что делают компиляторы, если у вас есть '#define defined (x) 1') –