какие директивы препроцессора могут использоваться для реализации стражей включения в с

Заголовочные файлы и стражи включения C/C++

Любой заголовочный файл C/C++ должен иметь следующую структуру.

Например, заголовочный файл myFunctions.h, в котором размещены объявления функций f и g, будет выглядеть так:

Зачем нужны заголовочные файлы

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

Указанное требование тривиально выполняется в простых случаях наподобие (считается, что компилятор просматривает программу сверху-вниз один раз — что, вообще говоря, неверно для современных компиляторов):

Однако если программу немного изменить, то требование уже нарушится:

Хотя в остальном эта программа вполне корректна. В случаях, когда такой порядок определения функций (сначала main, потом f) по какой-то причине более предпочтителен, можно использовать специальный элемент языка, называемый объявлением или прототипом функции f:

Объявление в первой строке сообщает компилятору, что вызовы функции f в дальнейшем тексте предполагают, что эта функция принимает один аргумент типа int и возвращает void.

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

Если функция определена в отдельном файле, то она может использоваться во многих других файлах, и в каждом таком файле придётся добавлять её объявление. Заголовочный файл представляет собой место, где собирается информация, которая возможно потребуется многим другим файлам. Объявления функций представляют классический пример такой информации. Директива препроцессора наподобие

вставляет целиком содержимое указанного заголовочного файла в текущее место исходного файла перед компиляцией (например, в main.c, если в нём встретилась эта строка). После такой вставки в main.c окажутся все объявления функций из файла myFunctions.h и компилятор будет счастлив.

В чём смысл стражей включения

Вкратце, директивы ifndef-define-endif, которые обрамляют любой грамотно оформленный заголовочный файл, являются трюком препроцессора: они обеспечивают то, что любой заголовочный файл будет включён в любой исходный файл не более одного раза.

Более подробно. Каждому заг. файлу «вручную» ставится в соответствие некоторый «символ», обычно связанный с именем этого файла, чтобы обеспечить уникальность. В первой строке проверяется, был ли уже определён этот символ ранее, если да, то весь остальной текст игнорируется. Если нет, то этот символ определяется, а затем вставляется и весь остальной текст заголовочного файла. Последняя строка (endif) просто означает закрытие такого «условного оператора».

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

Источник

Использование директив компиляции и инструкций препроцессора

Область применения: управляемое приложение, мобильное приложение, обычное приложение.

1. Директивы компиляции:

&НаКлиенте (&AtClient)
&НаСервере (&AtServer)
&НаСервереБезКонтекста (&AtServerNoContext)

следует применять только в коде модулей управляемых форм и в коде модулей команд. В остальных модулях рекомендуется применять инструкции препроцессору.

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

В противном случае невозможно гарантировать корректную работу клиент-серверных процедур и функций в различных режимах работы платформы 1С:Предприятие.

Функция КодОсновногоЯзыка() Экспорт
#Если НЕ ТонкийКлиент И НЕ ВебКлиент Тогда
Возврат Метаданные.ОсновнойЯзык.КодЯзыка;
#Иначе
Возврат СтандартныеПодсистемыКлиент.ПараметрКлиента(«КодОсновногоЯзыка»);
#КонецЕсли
КонецФункции

Функция КодОсновногоЯзыка() Экспорт
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
Возврат Метаданные.ОсновнойЯзык.КодЯзыка;
#Иначе
Возврат СтандартныеПодсистемыКлиент.ПараметрКлиента(«КодОсновногоЯзыка»);
#КонецЕсли
КонецФункции

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

В то же время, как и в обычных клиентских модулях, допустимо ветвление кода для учета специфики различных режимов работы клиентского приложения: веб-клиент, тонкий или толстый клиент (например, #Если ВебКлиент).

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

Процедура Пример1()
а = 1
#Область ИмяОбласти
+ 2;
#КонецОбласти // разрыв выражения
КонецПроцедуры

Результат = Пример4(Параметр1,
#Если Клиент Тогда
Параметр2, // некорректный вызов функции
#КонецЕсли
Параметр3);

Данные ошибки диагностируются автоматически с помощью среды разработки 1C:Enterprise Development Tools (EDT).

Правильно использовать инструкции препроцессора без разрыва конструкций.

Источник

Какие директивы препроцессора могут использоваться для реализации стражей включения в с

Заголовочные файлы включаются в текст программы с помощью директивы препроцессора #include. Директивы препроцессора начинаются со знака «диез» (#), который должен быть самым первым символом строки. Программа, которая обрабатывает эти директивы, называется препроцессором (в современных компиляторах препроцессор обычно является частью самого компилятора).
Директива #include включает в программу содержимое указанного файла. Имя файла может быть указано двумя способами:

определяет константу препроцессора BOOKSTORE_H. Поместив эту директиву непосредственно после директивы #ifndef, мы можем гарантировать, что содержательная часть заголовочного файла bookstore.h будет включена в исходный текст только один раз, сколько бы раз ни включался в текст сам этот файл.
Другим распространенным примером применения условных директив препроцессора является включение в текст программы отладочной информации. Например:

Если константа DEBUG не определена, результирующий текст программы будет выглядеть так:

В противном случае мы получим:

Есть константы, которые автоматически определяются компилятором. Например, мы можем узнать, компилируем ли мы С++ или С программу. Для С++ программы автоматически определяется константа __cplusplus (два подчеркивания). Для стандартного С определяется __STDC__. Естественно, обе константы не могут быть определены одновременно. Пример:

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

включает в текст программы содержимое файла cassert. Но поскольку все имена, используемые в стандартной библиотеке С++, определены в пространстве std, имя assert() будет невидимо до тех пор, пока мы явно не сделаем его видимым с помощью следующей using-директивы:

Если же мы включаем в программу заголовочный файл для библиотеки С

Источник

Урок №22. Директивы препроцессора

Обновл. 11 Сен 2021 |

Препроцессор лучше всего рассматривать как отдельную программу, которая выполняется перед компиляцией. При запуске программы, препроцессор просматривает код сверху вниз, файл за файлом, в поиске директив. Директивы — это специальные команды, которые начинаются с символа # и НЕ заканчиваются точкой с запятой. Есть несколько типов директив, которые мы рассмотрим ниже.

Директива #include

Вы уже видели директиву #include в действии. Когда вы подключаете файл с помощью директивы #include, препроцессор копирует содержимое подключаемого файла в текущий файл сразу после строки с #include. Это очень полезно при использовании определенных данных (например, предварительных объявлений функций) сразу в нескольких местах.

Директива #include имеет две формы:

Директива #define

Директиву #define можно использовать для создания макросов. Макрос — это правило, которое определяет конвертацию идентификатора в указанные данные.

Есть два основных типа макросов: макросы-функции и макросы-объекты.

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

Макросы-объекты можно определить одним из следующих двух способов:

#define идентификатор текст_замена

Макросы-объекты с текст_замена

Источник

Директивы препроцессора C#

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

Контекст, допускающий значение NULL

Директива препроцессора #nullable устанавливает контекст с заметками о допустимости значений NULL и контекст с предупреждениями о допустимости значений NULL. Эта директива определяет, действуют ли заметки, допускающие значение NULL, и могут ли быть заданы предупреждения о допустимости значений NULL. Каждый контекст либо отключен, либо включен.

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

Ниже приведены результаты использования директив:

Условная компиляция

Для управления условной компиляцией используются четыре директивы препроцессора.

Примечания

Для традиционных проектов, в которых не используется пакет SDK, необходимо вручную настроить символы условной компиляции для различных целевых платформ в Visual Studio с помощью страниц свойств проекта.

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

Определение символов

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

Директиву #define нельзя использовать для объявления значений констант, как это обычно делается в C и C++. Для определения констант в C# следует использовать статические элементы класса или структуры. При наличии нескольких констант имеет смысл создать для них отдельный класс «Constants».

Определение областей

Вы можете определить области кода, которые можно свернуть в структуру, используя следующие две директивы препроцессора.

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

Сведения об ошибках и предупреждениях

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

#error позволяет создать определяемую пользователем ошибку CS1029 из определенного места в коде. Пример:

Компилятор обрабатывает #error version особым образом и сообщает об ошибке компилятора CS8304 с сообщением, содержащим используемые версии компилятора и языка.

#warning позволяет создать предупреждение компилятора CS1030 первого уровня из определенного места в коде. Пример:

Директива #line позволяет изменять номер строки компилятора и при необходимости имя файла, в который будут выводиться ошибки и предупреждения.

В следующем примере показано, как включить в отчет два предупреждения, связанные с номерами строк. Директива #line 200 принудительно устанавливает номер следующей строки 200 (по умолчанию используется номер 6). До выполнения следующей директивы #line в отчете будет указываться имя файла Special. Директива #line default по умолчанию восстанавливает нумерацию строк в исходное состояние с учетом строк, номера которых были изменены с помощью предшествующей директивы.

В результате компиляции формируются следующие результаты:

Директива #line hidden скрывает последующие строки для отладчика. В этом случае при пошаговой проверке кода разработчиком все строки между #line hidden и следующей директивой #line (кроме случаев, когда это также директива #line hidden ) будут пропущены. Этот параметр также можно использовать для того, чтобы дать ASP.NET возможность различать определяемый пользователем и создаваемый компьютером код. В основном эта функция используется в ASP.NET, но также может быть полезна и в других генераторах исходного кода.

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

Директива #line filename задает имя файла, которое будет отображаться в выходных данных компилятора. По умолчанию используется фактическое имя файла с исходным кодом. Имя файла должно заключаться в двойные кавычки (» «). Перед ним должен указываться номер строки.

В следующем примере демонстрируется, как отладчик игнорирует скрытые строки кода. При выполнении этого примера будут показаны три строки текста. Тем не менее, если задать точку останова, как показано в этом примере, и нажать клавишу F10 для пошаговой отладки кода, отладчик игнорирует скрытую строку. Даже если точка останова установлена на скрытой строке, отладчик по-прежнему будет игнорировать ее.

Директивы pragma

Директива #pragma предоставляет компилятору специальные инструкции для компиляции файла, в котором она появляется. Компилятор должен поддерживать эти инструкции. Другими словами, директиву #pragma невозможно использовать для создания настраиваемых инструкций предварительной обработки.

pragma-name — имя распознанной прагмы, а pragma-arguments — аргументы, относящиеся к прагме.

#pragma warning

#pragma warning может включать или отключать определенные предупреждения.

warning-list — список номеров предупреждений с разделителем-запятой. Префикс CS является необязательным. Если номера предупреждений не указаны, disable отключает все предупреждения, а restore включает все предупреждения.

Чтобы найти номера предупреждений в Visual Studio, выполните сборку проекта, а затем поиск номеров предупреждений в окне Вывод.

#pragma checksum

Создает контрольные суммы для исходных файлов, чтобы помочь с отладкой страниц ASP.NET.

«filename» — это имя файла, для которого требуется наблюдение за изменениями или обновлениями, «» — глобальный уникальный идентификатор (GUID) для хэш-алгоритма, а «checksum_bytes» — строка шестнадцатеричных цифр, представляющих байты контрольной суммы. Должно быть четным числом шестнадцатеричных цифр. Нечетное число цифр приведет к выводу предупреждения во время компиляции, и директива будет пропущена.

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

Это решение не работает для проектов ASP.NET, так как рассчитанная контрольная сумма относится к созданному исходному файлу, а не файлу ASPX. Чтобы решить эту проблему, #pragma checksum предоставляет поддержку контрольных сумм для страниц ASP.NET.

При создании проекта ASP.NET в Visual C# созданный исходный файл содержит контрольную сумму для ASPX-файла, из которого создается источник. Затем компилятор записывает эти данные в PDB-файл.

Если компилятор не обнаруживает директиву #pragma checksum в файле, он вычисляет контрольную сумму и записывает значение в PDB-файл.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *