c препроцессором — распознавать нестандартный C ++ переносимо?

С имеет __STDC__ но, кажется, не существует стандартного способа распознавания некоторых расширенных диалектов C ++. Следовательно для переносимого кода я использую

#define __is_extended                                   \
((__GNUG__   &&!__STRICT_ANSI__)  ||                \
(_MSC_VER   && _MSC_EXTENSIONS && __cplusplus)  || \
(__IBMCPP__ && __EXTENDED__))

Пока это работает для gcc, XLC и Visual C ++.

Мы должны проверять соответствие ISO / ANSI индивидуально для каждого компилятора, верно? Если да, можете ли вы предложить другие компиляторы, которые доказали свою работоспособность?

РЕДАКТИРОВАТЬ: Поскольку было так много дискуссий о за и против таких испытаний, вот пример из реальной жизни. Скажи, что есть заголовок stuff.h широко используется с несколькими компиляторами в нескольких проектах. stuff.h использует некоторые специфичные для компилятора vsnprintf (не стандартизированный до C ++ 11), некоторые copy_if<> (они как-то пропустили это в C ++ 98), собственные мьютексные охранники и что не иначе. При реализации чистого варианта C ++ 11 вы оборачиваете старую (но надежную) реализацию в некоторые #if __is_extended (лучше: __is_idosyncratic или же !__is_ANSI_C11). Новый C ++ 11 идет за #else, Когда модуль перевода, который все еще компилируется как C ++ 0x или C ++ 98, включает stuff.h Ничего не изменилось. Нет ошибок компиляции, нет другого поведения во время выполнения. C ++ 11 остается экспериментальным. Код может быть безопасно передан в основную ветвь, сотрудники могут изучить его, извлечь уроки и применить методы с их компонентами.

2

Решение

Ваш вопрос на самом деле задом наперед, потому что нестандартные расширения, поддерживаемые компилятором, специфичны для этого компилятора — часто в той степени, в какой они специфичны для конкретной версии компилятора, — как и нестандартные макросы, которые каждый компилятор определяет, чтобы их можно было обнаружить ,

Обычный метод обратный: укажите какую-либо особенность, которую вы хотите, свяжите с каким-либо макросом и пишите код, который использует эту функцию, только если определен соответствующий макрос.

Допустим, есть какая-то интересная функция, которая поддерживается — точно так же в Visual C ++ 11 и g ++ версии 3.2.1, но не в каких-либо других компиляторах (даже в других версиях Visual C ++ или g ++).

//  in some header that detects if the compiler supports all sorts of features

#if ((defined(__GNUG__) && __GNUC__ == 3 && __GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ == 1) || (defined(_MSC_VER) && _MSC_VER == 1700))

#define FUNKY_FEATURE

#endif

// and, in subsequent user code ....

#ifdef FUNKY_FEATURE

// code which uses that funky feature

#endif

Существует множество свободно доступных библиотек общего назначения, которые используют эту технику (очевидно, с лучшим именованием макросов). Один пример, который приходит на ум, это Основа ACE (адаптивная коммуникационная среда) который имеет набор макросов переносимости, документирован Вот.

Использование таких макросов не является делом для слабонервных, если вас беспокоит большой набор нестандартных функций, учитывая, что необходимо понимать, какие версии каких компиляторов (или библиотек) поддерживают каждую функцию, и обновлять макросы каждый раз, когда выпускается новый компилятор, новая библиотека или даже патч.

Также необходимо избегать использования зарезервированных идентификаторов при именовании этих макросов и гарантировать, что имена макросов уникальны. Идентификаторы, начинающиеся с двойного подчеркивания, зарезервированы.

2

Другие решения

В общем, это будет трудно сделать, потому что если вы полагаетесь на несовместимый компилятор, то не существует стандартизированного способа требовать только стандартные правила (поведение нестандартного компилятора не определено стандартом).

То, что вы могли бы сделать, это добавить дополнительный шаг компоновки или перехватить фиксацию и передать код ТАКЖЕ через определенный переносимый компилятор (например, g ++) с конкретными параметрами строгого соответствия.

1

Во-первых, вы не можете называть переменные таким образом (#define __is_extended) потому что имена, начинающиеся с двух подчеркиваний, зарезервированы для реализации.

Ваш метод все еще зависит от компилятора и может потерпеть неудачу: кроме __cplusplusНи один из этих макросов не является стандартным, и поэтому для их определения не требуется реализация. Кроме того, этот тест в основном проверяет, какой компилятор используется, а не некоторые расширения являются использовался.

Мой совет просто не использовать расширения. Там очень очень мало необходимости в них. Если вы все равно хотите убедиться, что они не используются, вы можете включить флаги вашего компилятора, чтобы ограничить использование расширений; для GCC, есть целая глава об этом в разделе «Параметры управления диалектом C».

0
По вопросам рекламы [email protected]