Урок 12.5. Другие директивы
12.5. Другие директивы
Другие директивы препроцессора Си используются значительно реже, чем директивы #define, #include, директивы условной компиляции. К ним относятся директивы #undef, #error, #pragma и пустая директива #. Общая форма записи директивы #undef:
#undef <идентификатор>
Встретив директиву #undef, препроцессор считает <идентификатор> с этого момента неопределенным, то есть не подлежащим замене. Таким образом, препроцессор считает с того момента, как встретилась директива #undef, что для указанного идентификатора не выдавалась директива #define.
Пример:
#define BIG 500 . . . #undef BIG #define BIG 700 |
Если бы не было директивы #undef BIG, препроцессор выдавал бы предупреждение о переопределении константы, но так как директива #undef BIG есть, то в момент выполнения директивы #define BIG 700, BIG считается неопределенным идентификатором и никаких конфликтов не возникает.
Общая форма записи директивы #error:
#error <сообщение об ошибке>
Встретив эту директиву, компилятор прекращает свою работу и выдает следующее сообщение: Error directive:<сообщение об ошибке>
Здесь <сообщение об ошибке> – это то самое сообщение, которое указано в директиве #error.
Например:
#include "opersys.h" #if OS==UNIX #include "unix.h" #else #if OS==MSDOS #include "msdos.h" #else #error "Неизвестная ОС" #endif #endif . . . |
Пусть файл opersys.h содержит следующие строки:
#define MSDOS 1 #define UNIX 2 #define CPM 3 #define OS CPM |
При компиляции будет выдано следующее сообщение об ошибке: Error directive: " Неизвестная ОС"
Общая форма записи директивы #pragma:
#pragma warn +xxx или #pragma warn -xxx или #pragma warn .xxx |
Директива #pragma warn +xxx разрешает компилятору выдачу предупреждения с кодовым обозначением xxx. Директива #pragma warn -xxx запрещает компилятору выдачу предупреждения с кодовым обозначением xxx. Директива #pragma warn .xxx работает как переключатель, то есть если предупреждение xxx разрешено, директива #pragma warn .xxx запрещает его, а если запрещено - разрешает.
Например:
void main() { int i; i=10; } |
Если мы скомпилируем эту программу, компилятор предупредит нас, что переменной i присваивается значение, но переменная i нигде не используется в функции main(). Если же мы поместим в этом файле директиву препроцессора #pragma warn -aus, этого предупреждения не будет (aus – код предупреждения о том, что переменной присваивается значение, но она не используется).
Для завершенности Си опознает пустую директиву, состоящую из строки, содержащей просто знак #. Эта директива всегда игнорируется.
Урок 12.1. Определение символических констант
12.1. Определение символических
констант
Для определения символических констант служит уже знакомая Вам
директива #define. Как и все директивы препроцессора, директива #define начинается
с символа #. В простейшем случае общая форма записи директивы #define
следующая:
#define _идентификатор_ _строка подстановки_ |
Здесь _идентификатор_ - любое имя, записанное в соответствии с
правилами Турбо Си. _строка подстановки_ - строка, на которую замещается любое
вхождение _идентификатора_. Единственное исключение - если _идентификатор_
встречается в строке, заключенной в кавычки. В этом случае _идентификатор_
считается частью символьной строки и подстановка не производится. Определения,
даваемые директивой #define имеют силу от места, где встретилась эта директива
до конца файла.
Пример:
#define STRING1 "Это строка номер
один"
main ()
{
printf ("STRING1: %s\n",STRING1);
}
В результате работы этой программы будет напечатано:
STRING1: Это строка номер один
Как видим, в первом случае STRING1
не было замещено. И произошло это потому, что STRING1 "защищено" кавычками. _строка
подстановки_ должна уместиться физически в одной строке. В противном случае ее
можно перенести на следующую строку с помощью символа \.
Например, записи
#define STRING1 "Это строка \
номер один"
и
#define STRING1 "Это строка номер
один"
совершенно идентичны.
После того, как произведена подстановка, результирующая строка снова
просматривается и если в ней есть имена, определенные с помощью директивы #define, они замещаются соответствующими
подстановками.
Например, вследующемфрагменте:
#define ADDRESS BASE+OFFSET+INDEX
#define BASE 534
#define OFFSET 612
#define INDEX 163
. . .
x=ADDRESS;
после обработки строки x=ADDRESS; препроцессором, она превращается в x=BASE+OFFSET+INDEX; , которая в свою очередь после обработки
препроцессором превращается в x=534+612+163; и в таком виде передается
компилятору,а сложение производится уже при выполнении программы.
Если с помощью директивы #define
определено имя, ранее уже определенное с помощью другой директивы #define, препроцессор выдает предупреждение о
переопределении константы, но продолжает работать. Использование символических
констант чрезвычайно полезно, так как программы становятся более мобильными,
переносимыми. Кроме того, смысл таких констант яснее и программы легче
модифицировать.
Например:
int table[100]; /* количество элементов в
таблице */
#define NUM_ELEM 100
int table[NUM_ELEM]
Очевидно, что второе описание более наглядно, чем первое.