Запрещен ли #define отраслевыми стандартами?

Я учусь на первом курсе информатики, и мой профессор сказал, что #define запрещен отраслевыми стандартами вместе с #if, #ifdef, #else и некоторыми другими директивами препроцессора. Он использовал слово «забанен» из-за неожиданного поведения.

Это точно? Если да, то почему?

Существуют ли на самом деле какие-либо стандарты, запрещающие использование этих директив?


person psrag anvesh    schedule 28.12.2015    source источник
comment
Впервые я об этом услышал. Нет; #define и так далее. Иногда используется слишком широко, но определенно используется. Есть места, где стандарт C требует использования макросов - этого легко избежать. Вы можете проверить стандарты MISRA C; они склонны запрещать вещи, но я почти уверен, что даже они признают, что #define и др. иногда необходимы.   -  person Jonathan Leffler    schedule 28.12.2015
comment
Лучшее практическое правило - использовать #define только тогда, когда ничего другого не подойдет.   -  person August Karlstrom    schedule 28.12.2015
comment
Может быть, спросите, кто забанен, в каких отраслях, какие публикации связаны с этим предполагаемым запретом и т. Д.?   -  person Random832    schedule 28.12.2015
comment
Я уверен, что где-то есть хотя бы один стандарт, запрещающий #define.   -  person user253751    schedule 29.12.2015
comment
Ваш профессор не просто неправ, он комично неправ. Чтобы на самом деле сказать это с невозмутимым лицом, у них должен быть нулевой опыт и почти нулевые знания C. У этого человека нет бизнес-преподавания.   -  person Leushenko    schedule 29.12.2015
comment
@psraganvesh Возможно, ваш вопрос неправильно помечен? Вы имеете в виду C ++? Поскольку в C ++ есть больше способов обойти #define. Но он все еще ошибается.   -  person pipe    schedule 29.12.2015
comment
Забавная цитата о макросах в Руководстве по стилю Google: Вы не совсем собираетесь определить макрос, а? Если да, то они такие: MY_MACRO_THAT_SCARES_SMALL_CHILDREN.   -  person Danny_ds    schedule 29.12.2015
comment
Ваш профессор не ошибается. За исключением защиты включения, использование директив препроцессора широко запрещено в высоконадежных вычислениях.   -  person David Hammen    schedule 29.12.2015
comment
Соответствующие? twitter.com/ftrain/status/671394222218592256   -  person iKlsR    schedule 30.12.2015
comment
Может быть, английский не твой родной язык? Выбор слов здесь заставляет некоторых думать, что ваш профессор прав, а другие говорят, что он комично неправ. Нет организации, которая определяет отраслевые стандарты и имеет право запрещать макросы или любые другие языковые функции. Однако отраслевые передовые методы - то есть мнения и предложения умных и опытных профессионалов - обычно препятствуют использованию макросов препроцессора, если это не действительно необходимо.   -  person Kip    schedule 03.01.2016
comment
@Kip есть торговые организации, которые определяют операционные стандарты, с которыми корпорации должны согласиться, чтобы поддерживать код сертификации. ISO-9001 является одним из них, и их гораздо больше, и другими органами по сертификации. Я не могу сказать, заходят ли они так глубоко, чтобы определить подобное соглашение о коде, но я могу говорить от их имени, иногда имея подробные практические меры. Думаю, здесь есть стоящий вопрос.   -  person New Alexandria    schedule 10.01.2016


Ответы (13)


Впервые я об этом услышал.

Нет; #define и так далее. Иногда используется слишком широко, но определенно используется. Есть места, где стандарт C требует использования макросов - этого легко избежать. Например, в §7.5 Ошибки <errno.h> говорится:

Макросы

     EDOM
     EILSEQ
     ERANGE

которые расширяются до целочисленных константных выражений с типом int, отличными положительными значениями и которые подходят для использования в директивах предварительной обработки #if; …

Учитывая это, ясно, что не все отраслевые стандарты запрещают использование макросов препроцессора C. Однако существуют стандарты «передовой практики» или «руководящие принципы кодирования» от различных организаций, которые предписывают ограничения на использование препроцессора C, хотя ни один из них не запрещает его использование полностью - это врожденная часть C, и ее нельзя полностью избежать. Часто эти стандарты предназначены для людей, работающих в критических для безопасности областях.

Один из стандартов, который вы можете проверить - это стандарт MISRA C (2012); это имеет тенденцию запрещать вещи, но даже это признает, что #define и др. иногда необходимы (раздел 8.20, правила с 20.1 по 20.14 относятся к препроцессору C).

Стандарты кодирования C НАСА GSFC (Центр космических полетов Годдарда) просто говорят:

Макросы следует использовать только при необходимости. Чрезмерное использование макросов может затруднить чтение и поддержку кода, поскольку код больше не читает и не ведет себя как стандартный C.

Обсуждение после этого вступительного заявления иллюстрирует допустимое использование макросов функций.

В CERT Coding Standard есть ряд рекомендаций по использованию препроцессора и подразумевает, что вы должны минимизировать использование препроцессора, но не запрещает его использование.

Страуструп хотел бы, чтобы препроцессор не использовался в C ++, но этого еще не произошло. Как Питер примечания, некоторые стандарты C ++, такие как Стандарты кодирования JSF AV C ++ (Joint Strike Fighter, Air Vehicle) примерно с 2005 г. предписывают минимальное использование препроцессора C. По сути, правила JSF AV C ++ ограничивают его #include и танец #ifndef XYZ_H / #define XYZ_H /… / #endif, который предотвращает многократное включение одного заголовка. В C ++ есть некоторые параметры, которые недоступны в C - в частности, лучшая поддержка типизированных констант, которые затем можно использовать в тех местах, где C не позволяет их использовать. См. Также static const vs #define vs enum, где обсуждаются проблемы.

Рекомендуется свести к минимуму использование препроцессора - им часто злоупотребляют, по крайней мере, настолько, насколько он используется (см. Boost препроцессор 'библиотека' для иллюстраций того, как далеко вы можете зайти с препроцессором C).

Резюме

Препроцессор является неотъемлемой частью C и #define, #if и т. Д. Нельзя полностью избежать. Утверждение профессора в вопросе в целом неверно: #define запрещен отраслевыми стандартами вместе с #if, #ifdef, #else и некоторыми другими макросами в лучшем случае является преувеличением, но может быть поддерживаемым с явной ссылкой на определенные отраслевые стандарты (но рассматриваемые стандарты не включают ISO / IEC 9899: 2011 - стандарт C).


Обратите внимание, что Дэвид Хаммен имеет предоставила информацию об одном конкретном стандарте кодирования C - Стандарт кодирования C JPL - который запрещает многие вещи, которые многие люди используют в C, включая ограничение использования препроцессора C (и ограничение использования распределения динамической памяти и запрет рекурсии - прочтите его, чтобы узнать, почему, и решить, являются ли эти причины имеют отношение к вам).

person Jonathan Leffler    schedule 28.12.2015
comment
Некоторые из правил MISRA требуют / рекомендуют определенные ограничения на использование макросов, но они довольно разумны. На самом деле я был удивлен их вседозволенностью. Даже #define MAX(a,b) ((a>b)?(a):(b)) в порядке, несмотря на потенциальную опасность. - person Sneftel; 28.12.2015
comment
@Sneftel: Спасибо. Я не читал все правила MISRA (они в моем списке дел, но не с высоким приоритетом), но это был один из возможных источников отраслевого стандарта, который накладывает ограничения на ваши действия по сравнению с тем, что позволяет стандарт. - person Jonathan Leffler; 28.12.2015
comment
Существует ряд руководящих принципов или стандартов для критически важных для безопасности или критически важных разработок, которые запрещают использование макросов функций как в C, так и в C ++. - person Peter; 28.12.2015
comment
@Peter: можешь привести конкретный пример? MISRA не соответствует тому, что говорит Sneftel, и моему минимальному сканированию. Я просто зашел, чтобы проверить Стандарт кодирования C НАСА GSFC (Центр космических полетов Годдарда), и там написано: Макросы должны использоваться только при необходимости. Чрезмерное использование макросов может затруднить чтение и сопровождение кода, поскольку код больше не читает и не ведет себя как стандартный C., а продолжает пример макроса функции. - person Jonathan Leffler; 28.12.2015
comment
Прочтите 7.5 Ошибки в стандарте C. Это требует использования макросов. В прямом смысле. - person Andrew Henle; 28.12.2015
comment
@AndrewHenle: Великие умы думают одинаково - я как раз заканчивал редактирование и включил в текст именно §7.5 как пример того, где явно требуются макросы. - person Jonathan Leffler; 28.12.2015
comment
@JonathanLeffler - Продолжайте читать. ;) В стандарте написано, что неиспользование макроса errno приводит к UB. - person Andrew Henle; 28.12.2015
comment
Джонатон: Большинство, как вы говорите, не запрещают сразу. А вот пример C ++. Правило 29 JSF ++ AV гласит, что директива препроцессора #define не должна использоваться для создания встроенных макросов. Вместо этого должны использоваться встроенные функции. Правило AV 30 гласит, что директива препроцессора #define не должна использоваться для определения постоянных значений. Вместо этого к объявлениям переменных следует применять квалификатор const для определения значений констант. Правило AV 31 гласит, что директива препроцессора #define будет использоваться только как часть техники для предотвращения множественных включений одного и того же файла заголовка. - person Peter; 29.12.2015
comment
Я помню, как читал некоторые сопоставимые требования в других документах для C, но их нет под рукой. Я не припомню ни одного стандарта или директив, которые запрещали бы стандартной библиотеке / заголовкам использовать макросы [вероятно, слишком сложно добиться соответствия поставщика, или вынудили бы разработчиков адаптировать свою среду разработки, что было бы кошмаром обслуживания], но некоторые активно препятствуют использованию таких макросов. макросы (например, запрещение использования offsetof() и подобных макросов). - person Peter; 29.12.2015
comment
@Peter: спасибо за отзыв. Пожалуйста, посмотрите мое обновление. Использование offsetof() изредка, но очень редко, оправдано. - person Jonathan Leffler; 29.12.2015
comment
В организациях, у которых есть такие правила, они не запрещают использование макросов, уже определенных в стандарте (поэтому обсуждение errno и offsetof является спорным), и они не запрещают использование защиты включения. Вы можете столкнуться с такими правилами, если напишете программное обеспечение, которое может убить, может нанести ущерб на многие миллионы долларов или угрожать национальной безопасности. Если вы пишете видеоигру или базу данных, это не имеет значения. - person David Hammen; 29.12.2015

Нет, использование макросов не запрещено.

Фактически, использование #include предохранителей в файлах заголовков - это один из распространенных методов, который часто является обязательным и поощряется принятыми руководящими принципами кодирования. Некоторые утверждают, что #pragma once является альтернативой этому, но проблема в том, что #pragma once - по определению, поскольку прагмы - это ловушка, предоставляемая стандартом для расширений, специфичных для компилятора, - нестандартна, даже если она поддерживается рядом компиляторы.

Тем не менее, существует ряд отраслевых рекомендаций и рекомендуемых практик, которые активно препятствуют использованию любых макросов, кроме #include охранников, из-за проблем, которые вызывают макросы (несоблюдение объема и т. Д.). При разработке на C ++ использование макросов осуждается даже сильнее, чем при разработке на C.

Отговаривать от использования чего-либо - это не то же самое, что запрещать это, поскольку все еще можно законно использовать это, например, путем документального обоснования.

person Peter    schedule 28.12.2015

Некоторые стандарты кодирования могут препятствовать или даже запрещать использование #define для создания функционально-подобных макросов, которые принимают аргументы, например

#define SQR(x) ((x)*(x))

потому что а) такие макросы небезопасны по типу, и б) кто-то неизбежно напишет SQR(x++), что является плохим juju.

Некоторые стандарты могут препятствовать или запрещать использование #ifdefs для условной компиляции. Например, следующий код использует условную компиляцию для правильной печати значения size_t. Для C99 и более поздних версий вы используете спецификатор преобразования %zu; для C89 и более ранних версий вы используете %lu и приводите значение к unsigned long:

#if __STDC_VERSION__ >= 199901L
#  define SIZE_T_CAST
#  define SIZE_T_FMT "%zu"
#else
#  define SIZE_T_CAST (unsigned long)
#  define SIZE_T_FMT "%lu"
#endif
...
printf( "sizeof foo = " SIZE_T_FMT "\n", SIZE_T_CAST sizeof foo );

Некоторые стандарты могут предписывать, чтобы вместо этого вы реализовали модуль дважды, один раз для C89 и ранее, один раз для C99 и более поздних версий:

/* C89 version */
printf( "sizeof foo = %lu\n", (unsigned long) sizeof foo );

/* C99 version */
printf( "sizeof foo = %zu\n", sizeof foo );

а затем позвольте Make (или Ant или любой другой инструмент сборки, который вы используете) для компиляции и связывания правильной версии. Для этого примера это было бы нелепым излишеством, но я видел код, который представлял собой неотслеживаемое «крысиное гнездо» из #ifdef, в котором следовало выделить этот условный код в отдельные файлы.

Однако мне неизвестна какая-либо компания или отраслевая группа, которая полностью запретила использование инструкций препроцессора.

person John Bode    schedule 28.12.2015

Макросы нельзя «забанить». Утверждение - ерунда. В прямом смысле.

Например, раздел 7.5 Ошибки <errno.h> стандарта C Standard требует использования макросов:

1 Заголовок <errno.h> определяет несколько макросов, связанных с сообщением об ошибках.

2 Макросы

EDOM
EILSEQ
ERANGE

которые расширяются до целочисленных константных выражений с типом int, отличными положительными значениями и которые подходят для использования в директивах предварительной обработки #if; и

errno

который расширяется до изменяемого lvalue, имеющего тип int и длительность локального хранилища потока, значение которой устанавливается на положительный номер ошибки несколькими библиотечными функциями. Если определение макроса подавлено для доступа к реальному объекту или программа определяет идентификатор с именем errno, поведение не определено.

Таким образом, макросы не только являются обязательной частью C, в некоторых случаях их неиспользование приводит к неопределенному поведению.

person Andrew Henle    schedule 28.12.2015
comment
их неиспользование приводит к неопределенному поведению, которое не совсем похоже на то, что написано в тексте (или я неверно читаю / интерпретирую)? В нем говорится, что существует UB, когда либо определение макроса подавлено, либо определен идентификатор с именем errno, и я не понимаю, как вы проводите ссылку, чтобы не использовать макросы. Напротив, оба этих действия (подавление / определение) были бы типичными вещами, которые вы делаете при использовании макросов, а не когда их не используете? - person stijn; 28.12.2015
comment
@stijn - Как получить доступ к errno без использования макроса без вызова UB? В стандарте четко указано, что errno - это макрос, и четко указано, что подавление макроса errno или другое определение вашего собственного errno приводит к UB. И как вообще можно писать надежный код без использования errno? Некоторые системные вызовы все же можно прервать и вернуть ошибку с errno установлен в EINTR, даже если для всех ваших сигнальных флагов установлено SA_RESTART. Следовательно, если вы используете errno, вы не сможете писать код без макросов, если не вызовете UB. - person Andrew Henle; 28.12.2015
comment
да, это все правда, и я не защищаю, что нельзя использовать макросы, и определенно не следует использовать errno, а просто придирки, но ваш комментарий imo до сих пор не имеет личного доказательства того, что макросы не используются в своих собственных код каким-то образом приводит к UB. (обратите внимание на ваше последнее предложение если вы используете errno, поэтому, во-первых, если вы этого не сделаете, все в порядке (ну, вроде :), а во-вторых, даже если вы используете errno, вы на самом деле уже используете макросы, и вы мне все равно придется использовать больше макросов для вызова UB, так что опять же, это не не их использование - person stijn; 28.12.2015
comment
@stijn В моем ответе говорится: Итак, макросы являются не только обязательной частью C, в некоторых случаях их неиспользование приводит к неопределенному поведению. Раздел 7.5 явно делает макросы обязательной частью языка C. И если вы попытаетесь использовать errno без использования макроса required, вы вызовете UB. Прозрачный? - person Andrew Henle; 29.12.2015
comment
@Andew: Я считаю, что точка зрения stijn заключается в том, что существует различие между неиспользованием errno и использованием errno без использования макросов, и поэтому не их использование вызывает UB, а, скорее, их неправильное использование. Придирание к английскому языку, а не к C. - person Ray; 29.12.2015
comment
@Ray - Если вы используете errno без использования макросов, вы вызываете UB: Если определение макроса подавляется для доступа к реальному объекту ... поведение не определено. Это не имеет ничего общего с использованием макросы неправильно - если вы не используете макросы, но каким-то образом используете errno, вы вызвали UB. - person Andrew Henle; 29.12.2015
comment
Этот ответ настолько неординарный, что я должен проголосовать против него. Я работал в отраслях, где запрещено использование директив препроцессора. Они не запрещают использование errno или макросов, определенных в стандарте, и не защищают от множественного включения с помощью защиты включения. Это было бы нелепо. Что они действительно запрещают, так это использование #if и #define в любом контексте, кроме контекста включения. - person David Hammen; 29.12.2015
comment
@DavidHammen Этот ответ настолько неординарный, что я должен проголосовать против него. Я работал в отраслях, где запрещено использование директив препроцессора. Они не запрещают использование errno или макросов, определенных в стандарте, и не защищают от множественного включения с помощью защиты включения. Это было бы нелепо. Что они действительно запрещают, так это использование #if и #define в любом контексте, кроме контекста включения. Итак, вы работали там, где они запрещают макросы, кроме случаев, когда они этого не делают . Классная история. - person Andrew Henle; 30.12.2015
comment
@AndrewHenle - Исключения прописаны очень осторожно. Кроме того, речь шла об использовании #if и #define в пользовательском коде, а не об использовании директив препроцессора в системных заголовках. Обсуждение errno неуместно. - person David Hammen; 30.12.2015
comment
@DavidHammen Вопрос: Я студент первого курса информатики, и мой профессор сказал, что #define запрещен отраслевыми стандартами вместе с #if, #ifdef, #else и некоторыми другими директивами препроцессора ... НЕТ упоминания кода пользователя. errno является доказательством того, что утверждение - ерунда, потому что Стандарт C требует, чтобы errno был макросом - #define! - и поэтому следующие макросы не могут быть забанены. Тот факт, что ваши исключения изложены очень тщательно, является фактическим признанием с вашей стороны того, что они не запрещены. Это все равно, что сказать, что ограничение скорости запрещает вождение. - person Andrew Henle; 30.12.2015

Нет, #define не забанен. Однако неправильное использование #define может быть осуждено.

Например, вы можете использовать

#define DEBUG

в вашем коде, чтобы позже вы могли назначать части вашего кода для условной компиляции, используя #ifdef DEBUG, только для целей отладки. Не думаю, что кто-то в здравом уме захочет запретить что-то подобное. Макросы, определенные с помощью #define, также широко используются в переносимых программах для включения / выключения компиляции кода для конкретной платформы.

Однако, если вы используете что-то вроде

#define PI 3.141592653589793

ваш учитель может справедливо указать, что гораздо лучше объявить PI как константу с соответствующим типом, например,

const double PI = 3.141592653589793;

поскольку это позволяет компилятору выполнять проверку типов при использовании PI.

Точно так же (как упоминалось выше Джоном Боде) использование макросов, подобных функциям, может не одобряться, особенно в C ++, где можно использовать шаблоны. Так что вместо

#define SQ(X) ((X)*(X))

рассмотреть возможность использования

double SQ(double X) { return X * X; }

или, в C ++, еще лучше,

template <typename T>T SQ(T X) { return X * X; }

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

Когда у вас будет достаточно опыта программирования, вы будете точно знать, когда уместно использовать #define. А пока я думаю, что для вашего учителя будет хорошей идеей навязывать определенные правила и стандарты кодирования, но желательно, чтобы они сами знали и могли объяснить причины. Полный запрет на #define бессмысленен.

person Viktor Toth    schedule 28.12.2015

Это совершенно неверно, макросы широко используются в C. Новички часто используют их плохо, но это не повод запрещать их использование в промышленности. Классическое неправильное употребление - #define succesor(n) n + 1. Если вы ожидаете, что 2 * successor(9) даст 20, то вы ошибаетесь, потому что это выражение будет переведено как 2 * 9 + 1, т.е. 19, а не 20. Используйте круглые скобки, чтобы получить ожидаемый результат.

person mikedu95    schedule 28.12.2015
comment
Я не уверен, что этот пример четко оправдывает ложное использование новичками, - person psrag anvesh; 28.12.2015
comment
Верно, всем следует знать, что макросы должны расширяться до эквивалентов одного токена, что в значительной степени требует скобок в расширении… и аргументов: #define successor(n) ((n) + 1) - person mirabilos; 29.12.2015

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

person luis.espinal    schedule 28.12.2015
comment
Я бы сказал, мультиплатформенность и кросс-компилятор :) - person Andrea Corbellini; 28.12.2015
comment
Да неужели? Как создать платформу потоковой передачи, которая работает через потоки POSIX и / или Windows API, не полагаясь на сторонние прокладки (a-la cygwin или mingw)? Мы говорим не только об одной и той же ОС, нескольких аппаратных средствах, но и о нескольких ОС или поставщиках компиляторов. Вы когда-нибудь пытались поддерживать систему, ориентированную, скажем, на Linux и Integrity-OS, которые требуют разных компиляторов? Откажитесь от всего, что хотите. Факты на грязной земле в любом случае не изменятся. - person luis.espinal; 28.12.2015
comment
Я с тобой на 100% согласен. Я просто добавил, что препроцессор также полезен при написании кода кросс-компилятора. - person Andrea Corbellini; 28.12.2015

Нет, ваш профессор ошибается, или вы что-то не расслышали.

#define - это макрос препроцессора, и макросы препроцессора необходимы для условной компиляции и некоторых соглашений, которые просто не построены на языке C. Например, в недавнем стандарте C, а именно C99, была добавлена ​​поддержка логических значений. Но это поддерживается не языком "родным", а препроцессором #defines. См. эту ссылку на stdbool.h

person Superlokkus    schedule 28.12.2015
comment
он дважды сказал после того, как я спросил его во второй раз: «Запрещено в индустрии из-за неопределенного поведения, потому что я не слышал этого нигде больше». - person psrag anvesh; 28.12.2015
comment
неопределенное поведение? : | - person Andrea Corbellini; 28.12.2015
comment
@AndreaCorbellini Ага, он сказал, что не объясняет, что на самом деле такое неопределенное поведение - person psrag anvesh; 28.12.2015
comment
@psraganvesh Неопределенное поведение вызвано неправильным использованием языка C, а не просто использованием встроенных инструментов и концепций. Может быть, он имел в виду, потому что обычное использование часто приводит к неопределенному поведению, но есть сценарии в C, как я уже сказал, когда вы не можете обойти использование препроцессоров, и правильное использование IMHO часто приводит к лучшему коду. - person Superlokkus; 28.12.2015
comment
@psraganvesh Неопределенное поведение скорее вызвано, например, *NULL или char foo[2]; foo[2];, всеми ошибками программирования. Чтобы лучше узнать, что такое неопределенное поведение, часто сокращаемое до UB, я рекомендую следующее: c2.com/cgi/wiki ? UndefinedBehavior - person Superlokkus; 28.12.2015
comment
@psraganvesh Запрещение макросов приведет к неопределенному поведению в соответствии со стандартом C. См. Мой ответ относительно errno - в стандарте конкретно указано, что неиспользование макроса errno приводит к неопределенному поведению., - person Andrew Henle; 28.12.2015
comment
@psraganvesh Если ваш учитель на самом деле сказал, что #define, #if и т. д. ведет к неопределенному поведению, ему не следует не вести класс по C. Скорее всего, он никогда не писал код на C, и обманул себя с этой работой. Я бы рассмотрел возможность обсудить это с кем-нибудь выше. - person pipe; 29.12.2015

Макросы довольно часто используются в GNU land C, и без условных команд препроцессора нет способа правильно обрабатывать множественные включения одних и тех же исходных файлов, поэтому они кажутся мне важными языковыми функциями.

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

person Daniel Farrell    schedule 28.12.2015
comment
Лол, как я могу не знать, какой класс я слушаю, он специально сказал это дважды после того, как я спросил его во второй раз - person psrag anvesh; 28.12.2015
comment
Макросы также требуются в C ++. Например, нет другого способа (о котором я знаю) установить защиту заголовка (#ifndef HEADER_H #define HEADER_H ... #endif) - person R_Kapp; 28.12.2015
comment
@R_Kapp, вы никогда не слышали о #pragma once? Определенно найдите его - он еще не вошел в стандарт, но он поддерживается всеми поставщиками (GCC, Clang, EDG, MSVC, Intel, Green Hills, ARM, ...) и значительно снижает вероятность совершения глупых опечаток, таких как #ifndef FOO_H #define FOOH или #ifdef FOO_H #define FOO_H или использование одного и того же макроса в двух разных файлах .h. (Это также сокращает время компиляции и устраняет священные войны из-за интервалов и отступов в #ifndef-style include guard.) У условной компиляции, конечно, есть свои применения, но #pragma once бедняги не одно из них. - person Quuxplusone; 29.12.2015
comment
@Quuxplusone #pragma once почти наверняка не попадет в стандарт C в силу того, что является прагмой. Прагмы зарезервированы для поведения, определенного реализацией, поэтому добавление его в стандарт нарушит работу каждого компилятора, который его использовал, не соответствующим этому новому предполагаемому стандарту. Поэтому я бы сказал, что этого лучше избегать, если это возможно, и что это очень допустимое использование для #ifndef - person Vality; 29.12.2015
comment
@Vality Стандартные прагмы на самом деле полезны. :) Конечно, #pragma once может никогда не попасть в ISO C ++, потому что modules, вероятно, сделает файлы .h в значительной степени неактуальными в долгосрочной перспективе, но это не повлияет на комитет ISO C, насколько я могу знать. Они могли бы стандартизировать это завтра, если бы кто-нибудь написал предложение. - person Quuxplusone; 29.12.2015
comment
Чтобы внести что-то в стандарт, нужно больше, чем написать предложение. Смысл прагм - как в стандартах C, так и в C ++ - состоит в том, чтобы обеспечить ловушку для поведения, определенного реализацией, и реализации могут игнорировать любое использование #pragma. Поэтому предполагать, что любая прагма когда-либо будет стандартизирована, - просто фантазия - это понятие полностью расходится с тем, что такое прагмы. Тот факт, что некоторые поставщики неверно представляют некоторые из своих специфичных для них функций как стандартные, не означает, что это так. - person Peter; 29.12.2015

Вопреки всем ответам на сегодняшний день, использование директив препроцессора часто запрещается в высоконадежных вычислениях. Из этого правила есть два исключения, использование которых разрешено в таких организациях. Это директива #include и использование защиты включения в файле заголовка. Подобные запреты более вероятны в C ++, чем в C.

Вот только один пример: 16.1.1 Используйте препроцессор только для реализации защиты включения и включения файлов заголовков с защитой включения.

Другой пример, на этот раз для C, а не C ++: Стандарт институционального кодирования JPL для C Язык программирования. Этот стандарт кодирования C не заходит так далеко до полного запрета на использование препроцессора, но приближается к нему. В частности, в нем говорится

Правило 20 (использование препроцессора) Использование препроцессора C должно ограничиваться включением файлов и простыми макросами. [Сила десяти, правило 8].


Я не одобряю и не осуждаю эти стандарты. Но говорить, что их не существует, смешно.

person David Hammen    schedule 29.12.2015
comment
И вопрос помечен буквой C. - person jxh; 30.12.2015
comment
@jxh - И я работал в организациях, где были такие запреты, и в отношении C, а не C ++. Лично мне это не понравилось, но они есть. - person David Hammen; 30.12.2015
comment
Да, следствием этого является то, что он удаляет стандартизированный механизм генерации кода и приводит к взлому с использованием языков сценариев для генерации правильного исходного кода, а не условной компиляции. - person jxh; 30.12.2015
comment
То, что существует хотя бы одна среда, в которой запрещены макросы, совсем не то же самое, что сказать, что они запрещены во всей отрасли. Таким образом, существующие ответы не являются ни неправильными, ни смехотворными. - person Lightness Races in Orbit; 30.12.2015
comment
@LightnessRacesinOrbit - я не говорил, что они запрещены во всей отрасли. В наиболее оцененном (и ошибочно принятом IMNHO) ответе говорится: «Сначала я слышал об этом», а также в нескольких других ответах, в которых говорится что-то подобное. У нас есть профессор, который, возможно, знает только об одной отрасли, где использование препроцессора сильно ограничено, студент, который, скорее всего, неверно истолковал то, что сказал профессор, и куча ответов, которые чрезмерно интерпретировали этот неверно истолкованный вопрос. . Это не просто проблема XY. Это проблема XYZW. - person David Hammen; 31.12.2015
comment
Речь идет обо всей отрасли. - person Lightness Races in Orbit; 31.12.2015
comment
@LightnessRacesinOrbit - Это ваша интерпретация вопроса первокурсника. Часто нам приходится толковать вопросы студентов на этом сайте, потому что студенты даже более невежественны, чем профессора, которые их преподают. - person David Hammen; 31.12.2015
comment
@DavidHammen: Это действительно что-то говорит - person Lightness Races in Orbit; 01.01.2016

Если вы хотите, чтобы ваш код C взаимодействовал с кодом C ++, вы захотите объявить свои видимые извне символы, такие как объявления функций, в пространстве имен extern "C". Часто это делается с помощью условной компиляции:

#ifdef __cplusplus
extern "C" {
#endif

/* C header file body */

#ifdef __cplusplus
}
#endif
person jxh    schedule 29.12.2015
comment
Но это можно сделать с помощью #include "c++/header.h" в коде C ++, где файл "c++/header.h" содержит: extern "C" { / #include "c/header.h" / } (с одиночными косыми чертами, указывающими новые строки - и выбор имен подкаталогов, конечно, в значительной степени произвольный), что позволило бы избежать условной компиляции при стоимость дополнительного файла. Согласен, вы показываете то, что используется чаще всего (я сам этим пользуюсь). Но на самом деле в этом нет необходимости, если вы все настроили правильно. - person Jonathan Leffler; 01.01.2016
comment
Условную компиляцию можно заменить make-файлом, который выбирает разные исходные файлы в зависимости от условий. Это не делает его лучшим решением, он просто соответствует требованию no #if. Два файла заголовков, один из которых включает другой, просто создают вопросы. - person jxh; 01.01.2016

Посмотрите на любой заголовочный файл, и вы увидите что-то вроде этого:

#ifndef _FILE_NAME_H
#define _FILE_NAME_H
//Exported functions, strucs, define, ect. go here
#endif /*_FILE_NAME_H */

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

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

#ifdef __AVR__
//avr specific code here
#endif

Используя это в производственном коде, дополнительный тестовый код может компилироваться без использования avr-gcc, а приведенный выше код компилируется только с использованием avr-gcc.

person Dom    schedule 29.12.2015
comment
В организациях, которые запрещают использование процессора, охранники не считаются частью этого запрета. (Фактически, в таких организациях использование защитного ограждения является обязательным.) - person David Hammen; 29.12.2015

Если бы вы только что упомянули #define, я бы подумал, что, возможно, он имел в виду его использование для перечислений, которые лучше использовать enum, чтобы избежать глупых ошибок, таких как присвоение одного и того же числового значения дважды.

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

Однако добавить, что #if, #ifdef и т. Д. Не следует использовать, просто странно. Конечно, злоупотреблять ими, наверное, не стоит, но в реальной жизни есть десятки причин их использовать.

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

Это единственная интерпретация, которая имела бы смысл.

person jcaron    schedule 29.12.2015