Что такое директива в c
Перейти к содержимому

Что такое директива в c

  • автор:

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

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

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

Препроцессор распознает следующие директивы:

Знак номера ( # ) должен быть первым нехитовый символ в строке, содержащей директиву. Символы пробелов могут отображаться между знаком номера и первой буквой директивы. Некоторые директивы содержат аргументы или значения. Любой текст, следующий за директивой (кроме аргумента или значения, который является частью директивы), должен предшествовать одно строковый комментарий разделителя ( // ) или заключен в разделители комментариев ( /* */ ). Строки, содержащие директивы препроцессора, можно продолжить сразу перед маркером конца строки с обратной косой чертой ( \ ).

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

См. также

Дополнительные ресурсы

Значок отказа согласно Закону Калифорнии о защите конфиденциальности потребителей (CCPA)

  • Светлая
  • Темная
  • Высокая контрастность
  • Предыдущие версии
  • Блог
  • Участие в доработке
  • Конфиденциальность
  • Условия использования
  • Товарные знаки
  • © Microsoft 2024

Директива #define (C/C++)

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

Синтаксис

#define маркер-строкаидентификатора
#define идентификатор (идентификатор opt, . ,identifier opt)token-string opt

Замечания

Директива #define приводит компилятору заменить строку маркера для каждого вхождения идентификатора в исходном файле. Идентификатор заменяется только в том случае, если он формирует маркер. То есть идентификатор не заменяется, если он отображается в комментарии, в строке или в составе более длинного идентификатора. Дополнительные сведения см. в разделе «Токены».

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

Без #define строки маркера удаляется вхождения идентификатора из исходного файла. Идентификатор остается определенным и может быть проверен с помощью #if defined директив и #ifdef инструкций.

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

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

Формальные параметры в списке разделяются запятыми. Все имена в списке должны быть уникальными, и список должен быть заключен в скобки. Пробелы не могут разделять идентификатор и открываемую скобку. Используйте объединение строк — поместите обратную косую косую черту ( \ ) непосредственно перед новым символом — для длинных директив в нескольких исходных строках. Область формального имени параметра распространяется на новую строку, которая заканчивается строкой токена.

Если макрос определен во второй форме синтаксиса, последующие текстовые экземпляры, за которыми находится список аргументов, указывают на вызов макроса. Фактические аргументы, следующие за экземпляром идентификатора в исходном файле, соответствуют соответствующим формальным параметрам в определении макроса. Каждый формальный параметр в строке токена, который не предшествует строковой (), charizing ( #@ # ), или оператор вставки маркеров ( ## ) или не следует ## оператору, заменяется соответствующим фактическим аргументом. Перед заменой директивой формального параметра все макросы в фактическом аргументе разворачиваются. (Операторы описаны в разделе Операторы препроцессора.)

В следующих примерах макросов с аргументами показана вторая форма синтаксиса #define :

// Macro to define cursor lines #define CURSOR(top, bottom) (((top)  

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

Директива #undef приводит к тому, что определение препроцессора идентификатора забывается. Дополнительные сведения см . в директиве #undef.

Если имя определяемого макроса происходит в строке маркера (даже в результате другого расширения макроса), он не расширяется.

Второй #define для макроса с тем же именем создает предупреждение, если только вторая последовательность маркеров не идентична первой.

Блок, относящийся только к системам Майкрософт

Если новое определение синтаксически совпадает с исходным, Microsoft C и C++ позволяют переопределить макрос. Другими словами, два определения могут иметь разные имена параметров. Это поведение отличается от ANSI C, которое требует, чтобы два определения были лексически идентичны.

Например, следующие два макроса идентичны, за исключением имен параметров. ANSI C не разрешает такое переопределение, но Microsoft C/C++ компилирует его без ошибок.

#define multiply( f1, f2 ) ( f1 * f2 ) #define multiply( a1, a2 ) ( a1 * a2 ) 

С другой стороны, следующие два макроса неидентичны и приводят к выдаче предупреждения в Microsoft C и C++.

#define multiply( f1, f2 ) ( f1 * f2 ) #define multiply( a1, a2 ) ( b1 * b2 ) 

Завершение блока, относящегося только к системам Майкрософт

В этом примере показана директива #define :

#define WIDTH 80 #define LENGTH ( WIDTH + 10 ) 

Первый оператор определяет идентификатор WIDTH как целочисленную константу 80, а затем LENGTH задается в виде WIDTH и целочисленной константы 10. Каждое вхождение LENGTH заменяется на ( WIDTH + 10 ). В свою очередь, каждое вхождение WIDTH + 10 заменяется выражением ( 80 + 10 ). Скобки вокруг WIDTH + 10 имеют важное значение, поскольку управляют интерпретацией в операторах, например в следующем:

var = LENGTH * 20; 

После этапа предварительной обработки этот оператор принимает следующий вид:

var = ( 80 + 10 ) * 20; 

что равно 1800. Без скобок результат будет следующим:

var = 80 + 10 * 20; 

Блок, относящийся только к системам Майкрософт

Определение макросов и констант с параметром компилятора /D имеет тот же эффект, что и при использовании директивы предварительной обработки #define в начале файла. С помощью параметра /D можно определить до 30 макросов.

Завершение блока, относящегося только к системам Майкрософт

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

Директивы препроцессора представляют собой инструкции, записанные в тексте программы на СИ, и выполняемые до трансляции программы. Директивы препроцессора позволяют изменить текст программы, например, заменить некоторые лексемы в тексте, вставить текст из другого файла, запретить трансляцию части текста и т.п. Все директивы препроцессора начинаются со знака #. После директив препроцессора точка с запятой не ставятся.

1.8.1. Директива #include

Директива #include включает в текст программы содержимое указанного файла. Эта директива имеет две формы:

#include "имя файла" #include

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

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

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

1.8.2. Директива #define

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

Директива #define имеет две синтаксические формы:

#define идентификатор текст #define идентификатор (список параметров) текст

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

#define WIDTH 80 #define LENGTH (WIDTH+10)

Эти директивы изменят в тексте программы каждое слово WIDTH на число 80, а каждое слово LENGTH на выражение (80+10) вместе с окружающими его скобками.

Скобки, содержащиеся в макроопределении, позволяют избежать недоразумений, связанных с порядком вычисления операций. Например, при отсутствии скобок выражение t=LENGTH*7 будет преобразовано в выражение t=80+10*7, а не в выражение t=(80+10)*7, как это получается при наличии скобок, и в результате получится 780, а не 630.

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

При макровызове вслед за идентификатором записывается список фактических аргументов, количество которых должно совпадать с количеством формальных параметров.

Пример: #define MAX(x,y) ((x)>(y))?(x):(y) Эта директива заменит фрагмент t=MAX(i,s[i]); на фрагмент t=((i)>(s[i])?(i):(s[i]);

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

Например, при наличии скобок фрагмент t=MAX(i&j,s[i]||j); будет заменен на фрагмент t=((i&j)>(s[i]||j)?(i&j):(s[i]||j); а при отсутствии скобок - на фрагмент t=(i&j>s[i]||j)?i&j:s[i]||j; в котором условное выражение вычисляется в совершенно другом порядке.

1.8.3. Директива #undef

Директива #undef используется для отмены действия директивы #define. Синтаксис этой директивы следующий #undef идентификатор

Директива отменяет действие текущего определения #define для указанного идентификатора. Не является ошибкой использование директивы #undef для идентификатора, который не был определен директивой #define.

#undef WIDTH #undef MAX

Эти директивы отменяют определение именованной константы WIDTH и макроопределения MAX.

Что такое директива в c

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

#define идентификатор последовательность_символов

Определяемый идентификатор еще называют препроцессорным символом. Используем директиву #define:

#include #define N 23 int main(void) < int x = N; printf("Number: %d", x); // Number: 23 return 0; >

Здесь определен один идентификатор N. В программе, где встречается этот идентификатор, он будет заменяться на число 23. Например, строка

int x = N;

после обработки препроцессором будет иметь следующий код

int x =23;

Более сложный пример

#include #define BEGIN < #define END >#define N 23 int main(void) BEGIN int x = N; printf("Number: %d", x); // Number: 23 return 0; END

Здесь определены три идентификатора BEGIN, END, N. В итоге все вхождения последовательности символов "BEGIN" будут заменяться на открывающую фигурную скобку, а "END" - на закрывающую, а символ "N" на число 23.

Таким образом, после обработки препроцессора функция main приобретет следующий вид:

int main(void)

#define также может определять более сложные выражения. Например:

#include #define ADD(a,b) (a+b) int main(void) < int n1 = 10; int n2 = 5; printf("%d + %d = %d", n1, n2, ADD(n1, n2)); // 10 + 5 = 15 >

В данном случае выражение ADD(a,b) будет заменяться операцией сложения двух чисел (a + b)

Особенно удобно использовать директиву #define для определения размеров массивов:

#include #define N 4 int main(void) < int numbers[N] = ; for(int i=0; i return 0; >

В данном случае если мы захотим глобально поменять размер массива, то достаточно изменить значение N в директиве define.

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

#include #define N 4 int main(void) < char symbol = 'N'; printf("%c \n", symbol); // N printf("N"); //N return 0; >

Причем если идентификатор должен представлять одно слово, то его последовательность символов может состоять из нескольких слов или символов, разделенных пробелами:

#define REAL long double

Директива #undef

В процессе работы мы можем многократно определять новое значение для одного идентификатора:

#define N 23 #define N 32 #define N 55

Но некоторые компиляторы, в частности, gcc, могут выдавать предупреждения при повторном определении идентификатора, и чтобы выйти из этой ситуации, мы можем использовать директиву #undef для отмены действия макроса. Эта директива имеет следующее определение:

#undef идентификатор

#include #define STRING "Good morning \n" int main(void)

Определение крнстанты в командной строке

При использовании компилятора GCC мы можем с помощью флага -D определить константу аналогично, как это делается с помощью директивы %define . Для этого применяется выражение

gcc -D ИЛЕНТИФКАТОР=ЗНАЧЕНИЕ

Например, определим следующую программу:

#include int main(void)

В данном случае переменной x присваивается значение некоторого идентификатора NUMBER. Обратите внимание, что он нигде не определен, и среда разработки или текстовый редактор могут подчеркивать этот идентификатор как некорректный.

Теперь скомпилируем данную программу с помощью следующей команды (допустим, исходный файл называется "app.c"):

gcc -D NUMBER=25 app.c -o app.exe & app.exe

В данном случае мы определяем препроцессорный символ NUMBER и присваиваем ему значение 25. В итоге программа успешно скомпилируется, а переменная x получит значение 25.

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

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