Почему люди используют #ifdef для тестирования флагов объектов?

Люди рекомендуют #ifdef для условной компиляции с широким диапазоном. A поиск #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"

gcc -DIS_SPECIAL source.cpp

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

source1.cpp

#define IS_SPECIAL 1
#include "header.h"

Но так будет

source0.cpp

#define IS_SPECIAL 0
#include "header.h"

что совершенно неправильно. И некоторые компиляторы С++ передали файл, обработанный в режиме 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 отлично работает на именах undefined? Или существует ли фактический недостаток #if vs #ifdef для условной компиляции?


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

#ifndef MAX_FILES
#define MAX_FILES 64
#endif

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

Ответы

Ответ 1

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

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

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

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

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

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

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

Ответ 2

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

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

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

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