рефераты

рефераты

 
 
рефераты рефераты

Меню

Реферат: Turbo C++ Programer`s guide рефераты

Краткое изложение правил определения контекста С++

Следующие правила применимы ко всем именам, включая имена typedef и имена классов, при условии, что то или иноеимя допустимо в С++ в конкретном обсуждаемом контексте:

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

2. Если ошибок управления доступа не обнаружено, то проверяется тип объекта, функции, класса, typedef, и т.д.

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

4. Если имя n появляется в одном из видов: X::n, x.n (где x это объект класса Х или ссылка на Х), либо ptr->n (где ptrэто указатель на Х),то n является именем компонента Хили компонентом класса, производным от которого является Х.

5. Любое до сих пор не рассмотренное имя, используемое в качестве статической функции-компонента, должно быть объявлено в блоке, в которомоно встречается, либо в объемлющемблоке, либо являться глобальным именем. Объявление локального имени n скрывает объявления n в объемлющих блоках и глобальные объявления n. Имена в различныхконтекстах немогут быть перегружены.

6. Любое не рассмотренное до сих пор имя, используемое в качестве имени нестатической функции компонента класса Х, должно быть объявлено в блоке, в котором оно встречается, либо в объемлющем блоке, быть компонентом класса Х или базового относительно Х класса, либо быть глобальным именем. Объявление локального имени n скрывает объявления n в объемлющих блоках,компонентах класса- функциях и глобальных объявлениях n. Объявление имени компонента скрывает объявления этого имени в базовых классах.

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

8. Инициализатор конструктора (см. "инициализатор-конструктора" в описании синтаксиса декларатора класса в таблице

1.12 на стр.37 оригинала) вычисляется в контексте самого внешнего блока конструктора, и поэтому разрешает ссылки на имена аргументов конструктора.

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

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

CPP позволяет обращение к документации по нему в диалоговом режиме.

Следующее обсуждение директив препроцессора, их синтаксис и семантика, применимы, следовательно, как к самому препроцессору CPP, так и к его функциям, встроенным в компиляторы Turbo C++.

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

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

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

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

- Установка условной компиляции для улучшения мобильности получаемых кодов и для целей отладки.

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

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

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

Синтаксис директив препроцессора Turbo C++                                Таблица 1.23

файл-для-препроцессора:

группа

группа:

часть группы

группа часть-группы

часть-группы:

<лексемы-препроцессора> новая-строка

if-раздел

управляющая строка

if-раздел:

if-группа <elif-группы> <else-группа> endif-строка

if-группа:

#if  выражение-типа-константы  новая-строка  <группа>

#ifdef идентификатор новая-строка <группа>

#ifndef идентификатор новая-строка <группа>

elif-группы:

elif-группа

elif-группы  elif-группа

elif-группа:

#elif  выражение-типа-константы  <группа>

else-группа:

#else  новая-строка <группа>

endif-строка:

#endif новая-строка

управляющая-строка:

#include лексемы-препроцессора новая-строка

#define идентификатор список-замены новая-строка

#define идентификатор                                            левая-круглая-скобка

<список-идентификаторов>) список-замены новая-строка

#undef             идентификатор  новая-строка

#line                <лексемы-препроцессора> новая-строка

#pragma          <лексемы-препроцессора> новая-строка

#pragma          warn действие сокращение новая-строка

#pragma          inline  новая-строка

?               новая-строка

действие: одно из

+ - .

сокращение:

amb   ampapt   aus   big   cincpt

def   dupelf   mod   par   piapro

rch   retrng   rpt   rvf   sigstr

stu   stvsus   ucp   use   volzst

левая-круглая-скобка:

символ левой круглой скобки без предшествующих пробельных символов

список-замены:

<лексемы-препроцессора>

лексемы-препроцессора:

имя-заголовка (только для директивы #include)

идентификатор (без различения ключевого слова)

константа

строковый-литерал

операция

пунктуатор

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

имя-заголовка:

<последовательность-символов-заголовка>

последовательность-символов-заголовка:

символ-заголовка

последовательность-символов-заголовка  символ-заголовка

символ-заголовка:

любой символ из исходного множества символов, за исключением символа новой-строки (\n) или символа "больше чем" (>).

новая-строка:

символ новой строки

Пустая директива #

Пустая директива состоитиз строки, вкоторой содержится единственныйсимвол #. Эта директива всегда игнорируется препроцессором.

Директивы #define и #undef

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

Простые макросы #define

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

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

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

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

Пустая последовательность лексем позволяетэффективное удаление всех найденных идентификаторов макросов из исходного кода:

#define HI "Добрый день!"

#define empty

#define NIL ""

...

puts(HI);   /* расширяется в: puts("Добрый день!"); */

puts(NIL);   /* расширяется в: puts(""); */

puts("empty"); /* расширения empty не происходит ! */

/* расширение empty не будет выполнено и в комментариях! */

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

#define GETSTD #include <stdio.h>

...

GETSTD   /* ошибка компиляции */

GETSTD будет расширен в #include<stdio.h>. Однако, препроцессор не станет сам обрабатывать эту вполне допустимую в других условиях директиву, а передаст ее в таком виде компилятору. Компилятор воспримет#include <stdio.h> как недопустимый ввод. Макрос не может быть расширен во время собственногорасширения. Поэтому выражения типа #define A A недопустимы вследствие неопределенности результата.

Директива #undef

Можно отменить определение макроса при помощи директивы #undef:

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

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

Макрорасширения внутри строк #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);

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

Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40