2014-01-22 2 views
14

Люди recommend #ifdef for conditional compilation by a wide margin. A search for #ifdef обосновывает, что его использование широко распространено.Почему люди используют #ifdef для тестирования флагов объектов?

Еще #ifdef NAME (или, что эквивалентно #if defined(NAME) и связанной с ними #ifndef NAME#if !defined(NAME)) имеют серьезный недостаток:

header.h

#ifndef IS_SPECIAL 
#error You're not special enough 
#endif 

source.cpp

#include "header.h" 

НКУ - DIS_SPECIAL source.cpp

пройдет, очевидно, как будет

source1.cpp

#define IS_SPECIAL 1 
#include "header.h" 

Но, так будет

source0.cpp

#define IS_SPECIAL 0 
#include "header.h" 

, который совсем не то делать. И некоторые компиляторы C++ передали файл, обработанный в режиме C (из-за расширения или опции командной строки) эффективно делают #define __cplusplus 0. Я видел вещи ломаются, когда

#ifdef __cplusplus 
extern "C" { 
#endif 
/* ... */ 
#ifdef __cplusplus 
} 
#endif 

был обработан в C режима, где extern "C" недействителен синтаксис, поскольку __cplusplus был фактически автоматически определен в 0.

С другой стороны, это ведет себя правильно для всех компиляторов:

#if __cplusplus 
extern "C" { 
#endif 
/* ... */ 
#if __cplusplus 
} 
#endif 

Почему люди до сих пор используют #ifdef в этом сценарии? Неужели они просто не знают, что #if отлично работает с неопределенными именами? Или есть ли недостаток #if против #ifdef для условной компиляции?


Очевидно, что #ifdef имеет действительные применения, такие как обеспечение значения по умолчанию для настраиваемых параметров:

#ifndef MAX_FILES 
#define MAX_FILES 64 
#endif 

Я только обсуждающих случай тестирования флага.

+10

Почему это «совсем не то, что нужно делать»? Условие задает вопрос о том, что-то определено, и оно определено в обоих случаях. Можно было бы ожидать тех же результатов, нет? –

+2

@JoshuaTaylor: Это означает, что компилятор правильно выполнил тест. Это не означает, что пользователь выбрал правильный тест. См. Обсуждение '__cplusplus == 0', потому что это неправильный тест. Или вы считаете, что изменение параметра от «1» до «0» не должно отключать его? –

+2

To downvoter: Мне любопытно, что вы думаете, что этот вопрос плохо исследован? Это потому, что я не цитировал разделы Стандарта, которые имеют дело с '# if' и неопределенными макросами? Потому что вы не думаете, что ответ имеет практическую ценность? Потому что вопрос плохо написан и не может быть понят обычными программистами на C и C++? Я рад попытаться улучшить его, если вы дадите обратную связь. –

ответ

3

Почему люди все еще используют #ifdef в этом сценарии?

Личное мнение: его легко контролировать из командной строки. Я предпочитаю -DOPTION за -DOPTION=1.

Кроме того, существование названия явно двоичное. Мне не нужно обрабатывать {0, ненулевое, неопределенное}.

Неужели они просто не знают, что #if отлично работает на неопределенных именах?

Я не знал. Какова семантика этого? Не определено ли неопределенное имя 0? Должен ли я объяснить это парню, который с самого начала понимает препроцессор?

Или существует фактический недостаток #if vs #ifdef для условной компиляции?

Для меня двоичный характер #ifdef/#ifndef имени существования является ясностью. Кроме того, мое основное использование любой из этих конструкций - включение защитных устройств. Этот образец является самым чистым с #ifndef.

+3

Нет никакой разницы между '-DOPTION' и' -DOPTION = 1' (для любого препроцессора, который я когда-либо использовал). Оба определяют макрос 'OPTION' со значением' 1'. –

+1

Для C++, 16.1p4 определяет семантику '# if' на неопределенном имени, а именно:« После того, как все замены из-за расширения макроса и унарного оператора 'defined' были выполнены, все остальные идентификаторы и ключевые слова, за исключением истинных и ложных, заменяются с номером pp 0, а затем каждый токен предварительной обработки преобразуется в токен ». –

+0

@BenVoigt Чтобы все препроцессоры, представляющие интерес для вас, определяли макрос, определенный с помощью '-D',' 1', не гарантирует, что он останется таким. Сверху я вижу, что вас интересует переносимость кода C89 для разных старых компиляторов, но вы также можете быть заинтересованы в переносимости вашего кода для различных сценариев оболочки и препроцессоров. –

2

Я не могу говорить, почему люди вообще предпочитают #ifdef более #if, но я могу хотя бы сказать, почему я это делаю. Основываясь на интроспекции только сейчас (поскольку вы спросили - я никогда раньше не рассматривал это явно), есть две причины:

1) Я предпочитаю, чтобы мои макросы (которые я стараюсь использовать экономно) имели самую простую семантику насколько это возможно, и, соответственно, как «свободный тип». Я предполагаю, что макросы, если у них вообще есть какой-либо тип, являются либо «свободными функциями типа» (обратите внимание: здесь я бы сильно предпочел шаблоны, но бывают времена для всего ...) или в основном просто boolean flags. Следовательно, даже присвоение макросу значения 1 растягивает его для меня. (Например, что это значит, если у вас есть #define _cplusplus 2? Должно ли это быть каким-то иным образом, чем 1?)

2) Этот последний бит о них, являющийся «флагом», согласуется с тем, что я в основном использую их для вещи, которые я указываю в командной строке (или в среде IDE) как условная компиляция flags. Действительно, в моей команде разработчиков, когда мы пишем C++, мы в основном «запрещены» от использования макросов для чего-либо еще. И даже в случае условной компиляции мы стараемся избегать их, если мы можем решить проблему по-другому (например, через модульность).

Обе эти причины относятся к тому же основополагающему предположению о том, что использование макросов следует избегать как можно больше (на C++), и поэтому не должно быть сложностей типов или непрозрачной семантики. Если вы не сделаете это предположение (и это менее часто встречается при программировании на C, я знаю), то это меняет такие вещи, что, как я думаю, ваши очки о #if могут иметь более сильное влияние.

+0

FWIW, когда вы определяете флаг в командной строке с помощью '-D' и не указываете какое-либо конкретное значение, оно получает значение' 1'. –

+0

@BenVoigt Я это понимаю. Это все еще о различии между * flags * vs. * values ​​*. – Turix

+0

Как вы сами говорите, флаги являются логическими. Либо true, либо false. Ясно, что '1' истинно, и ясно (неопределено) ложно. Я думаю, что большинство людей также считают, что '0' является ложным, но для' # ifdef' это не так. –

 Смежные вопросы

  • Нет связанных вопросов^_^