46019 (665326), страница 22

Файл №665326 46019 (Turbo C++ Programer`s guide) 22 страница46019 (665326) страница 222016-07-31СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 22)

Данная строка удаляетлюбую ранее введенную последовательность лексем из идентификатора макроса;определение макроса теряется, и идентификатор его становится неопределенным.

Макрорасширения внутри строк #undef не выполняются.

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

После того, как идентификатор макроса стал

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

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

#define BLOCK_SIZE 512

...

buff = BLOCK_SIZE*blks; /* расширяется в: 512*blks */ ...

#undef BLOCK_SIZE

/* использование BLOCK_SIZE теперь невозможно - это "неизвестный" препроцессору идентификатор */

...

#define BLOCK_SIZE 128 /*переопределение размера блока*/

...

buf = BLOCK_SIZE*blks; /* расширяется в: 128*blks */

...

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

#ifndef BLOCK_SIZE

#define BLOCK_SIZE 512

#endif

Если идентификатор BLOCK_SIZE в текущий момент определен, то средняя строка не обрабатывается препроцессором; в противном же случае выполняется определение средней строки.

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

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

#define BLOCK_SIZE = 512 /* почему последовательность лексем включает символ = */

Опции -D и -U

Определение и отмена определения идентификаторов выполняется также при помощи опций компилятора командной строки - D и -U (см. Главу 4,"Компилятор командной строки" в Руководстве пользователя). Идентификаторы могут быть определены, но не могут бытьявно отменены, при помощи меню интегрированной среды разработки Options \! Compiler \! Defines (см. Главу 1,"Справочник по интегрированнойсредеразработки", также в Руководстве пользователя.)

Командная строка

tcc -Ddebug=1; paradox=0; X -Umysym myprog.c

эквивалентна помещению в программу строк:

#define debug 1

#define paradox 0

#define X

#undef mysym

Ключевые слова и защищенные слова

Допустимо, но не рекомендуется, использовать ключевые слова Turbo C++ в качестве идентификаторов макросов:

#define int long /* допустимо, но может привести к катастрофическим последствиям */

#define INT long /* допустимо и, вероятно, полезно */

Следующие предопределенные глобальные идентификаторы не могут появляться непосредственно следом за директивами #defineили #undef:

__STDC__ __DATE__

__FILE__ __TIME__

__LINE__

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

Макросы с параметрами

Для определения макросов с параметрами используется следующий синтаксис:

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

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

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

Вызов таких макросов выполняется записью

идентификатор-макроса()

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

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

Вызов макроса приводитк двум типамзамены. Во-первых, идентификатор макроса и заключенные в круглые скобки аргументы заменяются последовательностью лексем. Затем формальные аргументы, найденные в данной последовательности лексем, заменяются соответствующими фактическими аргументами из списка-фактических-аргументов. Например,

#define CUBE(x) ((x)*(x)*(x))

...

int n,y

n = CUBE(y):

дает в результате следующую замену:

n = ((y)*(y)*(y));

Аналогичным образом, последняя строка в

#define SUM ((a) + (b))

...

int i,j,sum;

sum = SUM(i,j);

при расширении даст sum = ((i)+(j)). Причина кажущегося избытка круглых скобок станет очевидной, если рассмотреть пример:

n = CUBE(y+1);

Без внутренней пары круглых скобок в определении расширение даст запись: n=y+1*y+1*y+1, что при лексическом анализе равно:

n = y + (1*y) + (1*y) + 1; // если y не равен 0 или -3, то в // куб возводится (y+1) !

Как и в случае простых макроопределений, производится повторное сканирование текста для определения необходимости повторных макрорасширений получившихся макро-идентификаторов.

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

1. Вложенные круглые скобки и запятые:

Список-фактических-аргументов может содержать вложенные круглые скобки, при условии соответствия числаоткрывающих числу закрывающих скобок; кроме того, запятые, заключенные во внутренние круглые скобки или кавычки, не рассматриваются в качестве разделителей аргументов:

#define ERRMSG(x, str) showerr("Error",x,str)

#define SUM(x,y) ((x) + (y))

...

ERRMSG(2, "Press Enter, then Esc");

// расширится в: showerr("Error",2,"Press Enter, then Esc"); */ return SUM(f(i,j), g(k.l));

// расширится в: return ((f(i,j)) + (g(k,l))); */

2. Склеивание лексем при помощи ##: можно выполнить склеивание (слияние) двух лексем, разделив их символами ## (и плюс опциональными пробельными символами с каждой стороны). Препроцессор удаляет пробельные символы и##, объединяядве отдельные лексемыв одну новуюлексему. Это средство можно использовать для конструированияидентификаторов; например, выполнив определение

#define VAR(i,j) (i##j)

и затем вызвав VAR(x,6), можно получить расширение (x6). Этот метод заменяет старый (не обеспечивающий мобильность кода) метод использования (i/**/j).

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

#define TRACE(flag) printf(#flag "=%d\n",flag)

фрагмент кода

int highval = 1024;

TRACE(highval);

станет равным

int highval = 1024;

printf("highval" "= %d\n", highval);

что в свою очередь будет рассматриваться как

int highval = 1024;

printf("highval=%d\n", highval);

4 Символ обратной наклонной черты для продолжения строки: длинная последовательность лексем может продлитьстрокупри помощи обратной наклонной черты (\). Символы обратной наклонной черты и новой строки оба вырезаются, и в результате образуется фактическая последовательность лексем, используемая в расширении:

#define WARN "фактически это одно\

строчное сообщение"

...

puts(WARN);

/* на экране будет: фактически это однострочное сообщение */

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

int cube(int x) (*

return x*x*x;

*)

#define CUBE(x) ((x)*(x)*(x))

...

int b =0, a = 3;

b = cube(a++);

/* cube() передается фактический аргумент = 3; поэтому b = 27, и теперь a = 4 */

a = 3;

b = CUBE(a++);

/* расширяется в: ((a++)*(a++)*(a++)); и теперь a = 6 */

Итоговое значение b зависит от того, что компилятор делает с расширенным выражением.

Включение файлов директивой #include

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

#include

#include "имя_заголовка"

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

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

Третий вариант записи предполагает, что ни символ <, ни символ " не являются первым не-пробельным символом, следующим за #include; кроме того, предполагается, что существует такое макроопределение, которое расширит идентификатор макроса в допустимое, следующее за разделителем имя заголовка в формате либо , либо "имя_заголовка".

Первый и второй варианты предполагают, что попыток макрорасширений сделано не будет; другими словами, имя_заголовка никогда не сканируется в поискахидентификаторов макросов. Имя_заголовка должно быть допустимым именем файла DOS с расширением (традиционно файлы заголовка имеют расширение .h) и опциональнымименемпути доступа к немус соответствующими разделителями.

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

Если поместить в имя_заголовка полное имя пути доступа к файлу, то поиск файла будет выполнентольков указанной таким образом директории.

Различиемежду форматами и "имя_заголовка" заключается в алгоритме поиска включаемого файла, применяемом в каждом случае; эти алгоритмы описаны в следующих двух разделах.

Поиск файла заголовка при формате

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

Поиск файла заголовка при формате "имя_заголовка"

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

Приводимые ниже примеры поясняют описанные различия:

#include

/* заголовок из стандартной включаемой директории */

#define myinclude"c:\tc\include\mystuff.h"

/* Примечание: здесь допустимы одинарные символы обратной

наклонной черты; в операторе С пишется:

"c:\\tc\\include\\mystuff.h" */

#include myinclude

/* макрорасширение */

#include "myinclude.h"

/* макрорасширение отсутствует */

После расширения второй оператор#include заставит препроцессор искать нужный файл в C:\TC\INCLUDE\mystuff.h, и нигде более. Третий пример #includeзаставляет препроцессор выполнить поискmyinclude.h сначала в текущей директории, а затем во включаемых директориях.

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

Turbo C++ поддерживаетусловную компиляцию путем замены соответствующих строк исходного кода пустой строкой. Игнорируемые таким образом строки это те строки, что начинаются с символа # (за исключением директив #if, #ifdef, #ifndef, #else, #elif и #endif), а также любые строки, которые в результате выполнения директив не должны компилироваться. Все директивы условной компиляции должны завершаться в том же исходном или включаемом файле, где находится их начало.

Директивы условной компиляции #if, #elif, #else и #endif

Директивы условной компиляции #if, #elif, #else и #endif работают аналогично обыкновенным условным операторам

С.Они используются следующим образом:

#if выражение-1-типа-константы

...

#endif

...

Если выражение-1-типа-константы(для котороговыполняется макрорасширение) дает ненулевое значение (истина), то строки кода (возможно, пустые), представленногоразделом-1, которые могут представлять собой как командные строки препроцессора, так и обычные строки исходного кода, обрабатываются препроцессором и соответствующим образом передаются компилятору Turbo C++. В противном случае, если выражение-1-типа-константы дает нулевое значение (ложь), раздел-1игнорируется (макрорасширение и компиляция данного раздела не выполняются).

В случае "истина" после обработки раздела-1 препроцессором управление передается соответствующейдирективе #endif (которая заканчивает даннуюусловную конструкцию) и продолжается в следующем-разделе. В случае "ложь" управление передается следующей строке #elif (если она определена в данной конструкции),где вычисляетсявыражение-2-типа-константы. В случае "истины" обрабатывается раздел-2, после чего управление передается соответствующей директиве #endif, и т.д.,до тех пор, пока не будет достигнута последняя директива #else или #endif. Опциональная директива #else используется в качестве альтернативного условия в том случае, если все предыдущие проверки дали значение "ложь". Последовательность условных директив заканчивается директивой #endif.

Характеристики

Тип файла
Документ
Размер
2,71 Mb
Тип материала
Учебное заведение
Неизвестно

Список файлов реферата

Свежие статьи
Популярно сейчас
Как Вы думаете, сколько людей до Вас делали точно такое же задание? 99% студентов выполняют точно такие же задания, как и их предшественники год назад. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6513
Авторов
на СтудИзбе
302
Средний доход
с одного платного файла
Обучение Подробнее