RSS    

   Реферат: Препроцессор языка C.

     Набор нестандартных заранее определенных символов в GNU C препроцессоре

изменяется (при компиляции самого компилятора) с помощью макроса

'CPP_PREDEFINES', которым является строка, состоящая из опций '-D',

разделенных пробелами. Например, на системе Sun 3 используется следующее

макроопределение:

     #define CPP_PREDEFINES "-Dmc68000 -Dsun -Dunix -Dm68k"

     Этот макрос обычно указывается в файле 'tm.h'.

     4.4. Стрингификация

     "Стрингификация" означает преобразование фрагмента кода в строковую

константу, которая содержит текст этого фрагмента кода. Например, в результате

стрингификации 'foo (z)' получается '"foo (z)"'.

     В С препроцессоре, стрингификация является опцией, используемой при

замене аргументов в макросе макроопределением. При появлении имени аргумента

в теле макроопределения, символ '#' перед именем аргумента указывает на

стрингификацию соответствующего аргумента при его подстановке в этом месте

макроопределения. Этот же аргумент может быть заменен в другом месте

макроопределения без его стрингификации, если перед именем аргумента нет

символа '#'.

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

     #define WARN_IF(EXP) \

     do { if (EXP) \

             fprintf (stderr, "Warning: " #EXP "\n"); } \

     while (0)

     Здесь аргумент 'EXP' заменяется один раз обычным образом (в конструкции

'if'), а другой - с использованием стрингификации (аргумет функции

'fprintf'). Конструкция 'do' и 'while (0)' является реализацией макроса

'WARN_IF (ARG);'.

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

аргумента в одну строковую константу: не существует методов комбинирования

аргумента с другим текстом и посследующей стрингификации полученных данных.

Хотя рассмотренный выше пример показывает как может быть достигнут подобный

результат в стандартном ANSI C  с использованием возможности объединения

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

значение 'EXP' в отдельную строковую константу и в результате получается

следующий текст:

     do { if (x == 0) \

             fprintf (stderr, "Warning: " "x == 0" "\n"); } \

     while (0)

но С компилятор обнаруживает три строковые константы, расположенные друг

за другом и объединяет их в одну:

     do { if (x == 0) \

             fprintf (stderr, "Warning: x == 0\n"); } \

     while (0)

     Стрингификация в С является не только заключением требуемого текста в

кавычки. Необходимо помещать символ backslash перед каждым дополнительным

символом кавычки, а также перед каждым символом backslash в символьной или

строковой константе для получения строковой константы в стандарте С. Поэтому

при стрингификации значения 'p = "foo\n";' в результате получится строка

'"p = \"foo\\n\";"'. Однако символы backslash, не принадлежащие символьной

или строковой константе, не дублируются: значение '\n' стрингифицируется в

'"\n"'.

     Пробелы (включая комментарии), находящиеся в тексте, обрабатываются

в соответствии с установленными правилами. Все предшествующие и последующие

пробелы игнорируются. Любые последовательности пробелов в середине текста

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

     4.5. Объединение

     "Объединение" означает соединение двух строковых констант в одну. При

работе с макросами, это означает объединение двух лексических единиц в одну

более длинную. Один аргумент макроса может быть объединен с другим аргументом

или с каким-либо текстом. Полученное значение может быть именем функции,

переменной или типа, а также ключевым словом С. Оно даже может быть именем

другого макроса.

     При определении макроса, проверяется наличие операторов '##' в его

теле. При вызове макроса и после подстановки аргументов все операторы '##',

а также все пробелы рядом с ними (включая пробелы, принадлежащие аргументам)

удаляются. В результате производится объединение синтаксических конструкций

с обоих сторон оператора '##'.

     Рассмотрим С программу, интерпретирующую указываемые команды. Для этого

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

следующим образом:

     struct command

     {

       char *name;

       void (*function) ();

     };

     struct command commands[] =

     {

       { "quit", quit_command},

       { "help", help_command},

       ...

     };

     Более удобным будет не указывать имя каждой команды дважды: один раз

в строковой константе, второй - в имени функции. Макрос, принимающий в

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

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

объединения аргумента со строкой '_command'. Ниже показано как это сделать:

     #define COMMAND(NAME)  { #NAME, NAME ## _command }

     struct command commands[] =

     {

       COMMAND (quit),

       COMMAND (help),

       ...

     };

     Обычным объединением является объединение двух имен (или имени и какого

либо числового значения) в одно. Также возможно объединение двух числовых

значений (или числового значения и имени) в одно. Операторы, состоящие из

нескольких символов (такие как '+='), также могут быть получены с помощью

объединения. В некоторых случаях возможно объединение строковых констант.

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

конструкции, не могут быть объединены. Например, объединение с одной стороны

символа 'x', а с другой - '+' является бессмысленным с точки зрения

формирования лексических конструкций С. В стандарте ANSI указано, что

подобный тип объединения не определен, хотя препроцессор GNU C их определяет.

В данном случае он помещает вместе символы 'x' и '+' вместе без каких либо

побочных эффектов.

     Следует заметить, что препроцессор С преобразует все комментарии в

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

путем объединения '/' и '*' так как последовательность символов '/*' не

является лексической конструкцией. Также можно использовать комментарии в

макроопределениях после строки '##' или в объединяемых аргументах, так как

сначала комментарии заменяются на пробелы, а при объединении эти пробелы

игнорируются.

     4.6. Удаление макросов

     "Удалить" макрос означает отменить его определение. Это производится с

помощью директивы '#undef', за которой следует имя макроса.

     Как и определение, удаление макросов появляется в определенном месте

исходного файла и вступает в силу с этого места. Например,

     #define FOO 4

     x = FOO;

     #undef FOO

     x = FOO;

заменяется на

     x = 4;

     x = FOO;

     В этом примере значение 'FOO' должно быть лучше переменной или

функцией, чем макросом, для получения после подстановки правильного С кода.

     Директива '#undef' используется в такой же форме и для отмены

макроопределений с аргументами или без них. Применение этой директивы к

неопределенному макросу не дает никакого эффекта.

     4.7. Переопределение макросов

     "Переопределение" макроса означает определение (с помощью директивы

'#include') имени, которое уже было определено как макрос.

     Переопределение явялется простым, если новое определение явно

идентично старому. Иногда не требуется специально выполнять простое

переопределение, хотя оно производится автоматически, если подключаемый

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

эффекта.

     Нетривиальные переопределения рассматриваются как возможная ошибка,

поэтому в таких случаях препроцессор выдает предупреждающее сообщение.

Однако, это иногда помогает при изменении определения макроса во время

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

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

'#undef'.

     Для простого переопределения новое определение долно точно совпадать

с предыдущим значением за исключением двух случаев:

     В начале и в конце определения могут быть добавлены или удалены пробелы.

     Пробелы можно изменять в середине определения (но не в середине

строки). Однако они не могут быть полностью удалены, а также не могут быть

вставлены туда, где их не было вообще.

     4.8. Особенности использования макросов

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

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

случаи, которые следует иметь в виду.

     4.8.1.  Неправильно используемые конструкции

     При вызове макроса с аргументами, они подставляются в тело макроса, а

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

частью исходного файла на предмет дополнительных макро вызовов.

     Возможно объединение макро вызова, исходящего частично от тела макроса

Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10


Новости


Быстрый поиск

Группа вКонтакте: новости

Пока нет

Новости в Twitter и Facebook

                   

Новости

© 2010.