Реферат: Turbo C++ Programer`s guide
6. Тело функции, представляющее собой коды, выполняемые при вызове
функции.
Объявления формальных параметров
Список объявления формальных параметров имеет
синтаксис, аналогичный синтаксису обычных объявлений идентификаторов. ниже
приводится несколько примеров:
int func(void) (* //
аргументы отсутствуют
С++int func(T!
t1, T2 t2, T3 t3=1) (*
// три
простых параметра,
// один из
которых с аргументо
// по умолчанию
C++int
func(T1* ptr1, T2& tref) (*
// аргументы указатель и ссылк
int func(register int i) (* // запрос
регистра для аргумен
int func(char *str,...) (* /* один строковый аргумент ипеременное число
прочих аргументов, либо фиксированное число аргументов с переменными типами */
В С++ вы можете задавать, как показано, аргументы по
умолчанию. Параметры со значениями по умолчанию должны являться последними
параметрами в списке. Типы аргументов могут быть скалярными,
структурами,объединениями, перечислимого типа, указателямиили ссылками на
структуры или объединения, или указателями на функции или классы.
Многоточие (...) означает, что функция будет вызываться в разных случаях
с различными наборами аргументов. Многоточие может следовать за подсписком
объявлений известных аргументов. Такая форма прототипа уменьшает число
выполняемых компилятором проверок.
Все объявленные параметры автоматически получают контекст, а также
длительность данной функции. Единственным допустимым для них классом
спецификатора является register.
В деклараторах формальных параметров могут использоваться модификаторы
const и volatile.
Вызовы функций и преобразования
аргументов
Функция вызывается с фактическими аргументами, помещенными в той же
последовательности,что и соответствующие им формальные аргументы.
преобразования фактических аргументов выполняется,как если бы
ониинициализировались значениями формальных аргументов при объявлении типов.
Ниже приводится краткое изложение правил, управляющих обработкой в Turbo
C++ модификаторов языка и формальных параметров при вызове функций, как при
наличии прототипа, так и при его отсутствии:
1. Модификаторы языка для определения функции должны соответствовать
модификаторам, используемым в объявлении функции, при всех вызовах функции.
2. Функция может модифицировать значения своих формальных параметров, но
это не влияет на фактические аргументы в вызывающей программе, за исключением
аргументов типа ссылка в C++.
Если ранее не был объявлен прототип функции, Turbo C++ преобразует
интегральные аргументы при вызове функции в соответствии с правилами
интегрального расширения, описанными в разделе "Стандартные
преобразования" на стр.41 оригинала. При наличии в контексте прототипа
функции Turbo C++ преобразует данные аргументы к объявленным типам параметров,
как при операции присвоения.
Если прототип функции включает в себя многоточие (...), то Turbo C++ преобразует
все данные аргументы функции, как и в любом другом прототипе (использующем
многоточие). Компилятор расширяет любые аргументы, заданные помимо
фиксированных параметров, по обычным правилам для аргументов функции без
прототипов.
При наличии прототипа число аргументов в прототипе и
функции должно совпадать (при условии, что в прототипе не задано
многоточие).Типы аргументов должны являться совместимы в такой степени, чтобы
операция присвоения выполнялась правильно. Вы всегда можете использовать явные
приведения, чтобы преобразовать аргумент к типу, приемлемому для прототипа
функции.
Важное замечание
Если прототип функции не соответствует фактическому определению функции,
Turbo C++ обнаружит это в том и том случае, когда определение содержится в той
же единице компиляции, что и прототип. При создании библиотеки подпрограмм с
соответствующим файлом заголовкапрототипов незабывайте включать этот файл при
компиляции библиотеки, с тем, чтобы любые расхождения между прототипом и
фактическими определениями функции были обнаружены. С++ обеспечивает при
компоновке контроль типов, поэтому все различия между ожидаемыми и
действительно заданными параметрами будут компоновщиком обнаружены.
Структуры
Инициализация структуры описана
на стр.42 оригинала.
Структура - это производный тип данных, обычно
представляющий собой определяемый пользователем набор именованных компонентов.
Эти компоненты могут быть любого типа, как фундаментального, так и производного
(с некоторыми описываемыми далее ограничениями), и располагаться в любой
последовательности. Кроме того, компонент структуры может иметь тип битового
поля, более нигде не разрешаемого. Тип струтуры в Turbo C++ позволяет
обрабатывать сложные структуры данных так же легко, как и простые переменные.
В С++ тип структуры рассматривается как тип класса (с
определенными различиями: доступ по умолчанию устанавливается public, а
умолчание для базового класса также public). Это позволяет организовывать более
сложное управление компонентами структуры при помощи спецификаторов доступа
С++: public (это умолчание), private и protected. Помимо данного опционального
механизма управления доступом и упомянутых исключений, далее рассматриваемые
синтаксис и применение структур относятся равно к структурам С и С++.
Объявление структур выполняется при помощи ключевого слова
struct. Например,
struct mystruct (* ... *); // mystruct - это тег структуры
...
struct
mystruct s, *ps, arrs[10];
/* s имеет тип структуры mystruct; ps это указатель
на тип struct mystruct */
Структуры без тегов и
определения типов (typedef)
Структуры без компонентов и компоненты объединений
при инициализации игнорируются.
Если тег структуры опущен, то получается структура без
тега. Такуюструктуру можно использовать для объявления идентификаторов в
разделяемом запятыми списке-идентификаторов-структуры как имеющих данный тип
структуры (или являющихся производными от него), но объявлять объекты этого
типа дополнительно где-либо еще нельзя:
struct (* ...*) s, *ps,
arrs[10]; //структура без тега
При объявлении структуры, как с тегом, так и без
него, можно создать typedef:
typedef
struct mystruct (* ... *) MYSTRUCT;
MYSTRUCT s,
*ps, arrs[10]; // то же, что и
// struct
mystruct s и т.д.
typedef struct (* ... *) YRSTRUCT; // тег
отсутствует YRSTRUCT y, *yp, arry[20];
Обычно и тег, и typedef одновременно не нужны;
вобъявлениях структуры может быть использован любой из них.
Объявления компонентов структуры
Список-объявления-компонентов вфигурных скобках
объявляет типы и имена компонентов структуры при помощи синтаксиса декларатора,
показанного в таблице 1.11 на стр.36 оригинала.
Компоненты структуры могут быть любого типа, за двумя исключениями
1. Тип компонента не может быть тот же, что и объявляемая в текущий
момент структура:
struct mystruct (* mystruct s *)
s1, s2;// недопустимо
Компонент структуры может являться указателем на объявляемую структуру,
как в следующем примере:
struct mystruct (* mystruct *ps
*) s1, s2; // так можно
Кроме того, структура может содержать ранее
объявленные типы структур, объявляя вхождения объявленных ранее структур.
В
С++ ключевое слово struct может быть опущено.
2. Кроме С++, компонент структуры нигде не может
иметь тип "функция, возвращающая ...", но тип "указатель на
функцию, возвращающую ..." допустим. В С++ struct может иметь
компоненты-функции.
Структуры и функции
Функция может иметь возвращаемое значение типа структуры или указателя
структуры.
mystruct func1(void); // func1() возвращает структуру
mystruct
*func29void); // func2()
возвращает указатель структуры
Структура можетбыть передана функции в качестве
аргумента, следующим образом:
void func1
(mystruct s); // непосредственно
void func2
(mystruct *sptr); // через указатель
void func3 (mystruct &sref); // по ссылке
(только С++) Доступ к компоненту структуры
Доступ к компонентам структур и объединений выполняется
операторами выбора . и ->. Предположим, что объект имеет тип структуры S, а
sptr это указатель на S. Тогда, если m это идентификатор типа M, объявленного в
S, то выражения s.m и sptr->m имеют тип M и представляют объект m - компонент
структуры s. Выражение s->sptr является удобным синонимом (* sptr).m.
Операция . называется прямым селектором компонента
структуры; операция -> называется косвенным селектором компонента (или
указателем) структуры; например,
struct
mystruct (*
int i;
char str[21];
double d;
*) s,
*sptr=&s;
...
s.i = 3; // присвоению члему i структуры mystruct s
sptr->d = 1.23; // присвоение компоненту d структуры mystruct s
Выражение s.m является именуемым значением (lvalue), если
s это не именуемое значение и s не имеет тип массива. Выражение sptr->m
является именуемым выражением, если m не имеет тип массива.
Если структура B содержит поле, тип которого есть структура A, то доступ
к компонентам A выполняется через два одновременно задаваемых селектора
компонента структуры:
struct A (*
int j;
double x;
*)
struct B (*
int i;
struct A a;
double d;
*) s, *sptr;
...
s.i = 3; // присвоение компоненту i структуры B
s.a.j = 2; // присвоение компоненту j структуры A sptr->d = 1.23; //
присвоение компоненту d структуры B (sptr->).x = 3.14 // присвоение
компоненту x структуры A
Каждое объявление структуры вводит уникальный тип
структуры, поэтому в
struct A (*
int i,j;
double d;
*) a, a1;
struct B (*
int i,j;
double d;
*) b;
объекты a и a1 оба имеют тип struct A, но объекты a и b имеют различные
типы структуры. Структурам может выполняться присваивание только в том случае,
если и исходная структура, и структура назначения имеют один и тот же тип:
a = a1;// так можно; тип один и тот же, поэтому может быть
// выполнено покомпонентное присвоение структур
a = b;// так
нельзя; разные компоненты
a.1 = b.1; a.j = b.j; a.d = b.d; // однако
присвоение можно // выполнять на уровне компонентов структуры
Выравнивание по границе слова
Память распределяется структуре покомпонентно,
слева-направо, от младшего к старшему адресу памяти. В следующем примере
struct
mystruct (*
int i;
char str[2];
double d;
*) s;
объект s занимает достаточное количество памяти для
размещения 2- байтового целочисленного значения, 21-байтовой строки и
8-байтового значения типа double. Формат данного объекта в памяти определяется
опцией Turbo C++ выравнивания по границе слова. Когда эта опция выключена (по
умолчанию), s будет занимать 31 байт непрерывно. Если же включить выравнивание
по границе слова опцией -a компилятора (или в диалоговом поле Options \!
Compiler \! Code Generation), то Turbo C++ заполняет структуры байтами таким
образом, что структура была выравнена по следующим правилам:
1. Структура должна начинаться по границе слова (четный адрес).
2. Любой не-символьный элемент будет иметь четное смещение
в байтах относительно начала структуры.
3. В конец структуры при необходимости добавляется
конечный байт, таким образом, чтобы вся структура в целом занимала четное
количество байтов.
Если опция выравнивания включена, топриведенный пример
структуры имел бы добавленный перед double байт, и весь объект в целом занимал
бы 32 байта.
Пространство имен структур
Имена тегов структур разделяют общее пространство
имен стегами объединений и перечислимых данных (однако в С++ имена входящих в
структуру перечислимых данных находятсяв другом адресном пространстве). Это
означает, что в пределах одного контекста такие теги должны иметь уникальные
имена. Однако, имена тегов не обязаны отличаться от идентификаторов,
находящихся в трех других адресных пространствах: пространстве имен меток,
пространстве (пространствах) имен компонентов и едином адресном пространстве
(которое состоит из имен переменных, функций, имен typedef и нкмераторов).
Имена компонентов в пределах данной структуры или
объединения лбязаны быть уникальными, но среди разных структур или объединений
они могут совпадать. Например,
goto s;
...
struct s (* // так можно; теги и имена меток
находятся в разных // адресных пространствах
int s; // так можно; теги, имена меток и имена
компонентов // дятся в разных адресных пространствах
float s;// так нельзя: повторение имени компонентов
структур *) s; // так можно; пространства имен переменных различны // В С++ это
допустимо только если s не имеет
// конструктора.
union s (* // так нельзя: повторение имен в
пространстве тегов int s; // так можно: новое пространство компонентов float f;
*) f; //
так можно: пространство имен переменных
struct t (*
int s; // так можно: следующее пространство имен компоненто
...
*) s; //
так нельзя: повторение имен переменных
Неполные объявления
Указатель структуры типа А допустим в объявлении другой структуры В до
объявления структуры А:
struct A;// неполное объявление struct B (* struct A *pa
*);
struct A (* struct B *pb *);
Первое объявление А называется неполным, поскольку
в этой точке отсутствует определение А. В данной ситуации неполное объявление
допустимо, поскольку в объявлении В размер А необязателен. Битовые поля
Структура можетсодержать любые комбинации битовых полей с данными других
типов.
Целочисленные компоненты типа signed или unsigned можно объявить битовыми
полями шириной от 1 до 16 бит. Ширина битового поля и его опциональный
идентификатор задаются следующим образом:
спецификатор-типа
<идентификатор-битового поля>:ширина;
где спецификатор-типа это char, unsigned char, int
или unsigned int. Битовые поля располагаются с нижнего и кончая саршим битом
слова. Выражение "ширина" должно быть задано и должно давать
целочисленную константу со значением в диапазоне от 0 до 16.
Если идентификатор битового поля опущен, то число битов,
заданное выражением "ширина", распределяется в памяти, но поле при
этом остается недоступным программе. Это позволяет создавать битовые шаблоны
для, например, аппаратных регистров компьютера, в которых некоторые биты не
используются. Пример:
struct
mystruct (*
int i:2;
unsigned
j:5;
int :4;
int k:1;
unsigned
m:4;
*) a, b, c;
создает следующее распределение
памяти.
\! |
\! 15\!
4 \! 3 \!
|
14\! 13\! 12\!
11\! 2 \! 1 \! 0 \! |
10\! |
9 |
\ |
8 |
\! |
7 |
\! |
6 |
\! |
5 |
\! |
\! x \!
x \! x \!
|
x \! x \! x
\! x \!
x \! x \!
x \!
|
x \! |
x |
\ |
x |
\! |
x |
\! |
x |
\! |
x |
-- |
\!<----
->\!<----
|
-------->\!<->\!<---
>\!
|
---- |
- |
- |
>\ |
<- |
- |
-- |
- |
-- |
- |
\ |
m \! k \ |
не используется\! |
j |
\ |
|
i |
\! |
|
|
|
|
|
Целочисленные поля хранятся в виде дополнения до двух,
причем крайний левый бит побещается в MSB (наиболее значащий бит).Для битового
поля типа Int (например, signed) MSB интерпретируется как знаковый бит. Битовое
поле шириной 2, содержащее двоичное 11, будет, следовательно, в случае типа
unsigned интерпретироватьсякак 3, а в случае Int как -1. В предыдущем примере
допустимое выражение a.i = 6 поместит в a.i двоичное 10 = -2, не выдавая
каких-либо предупреждений. Поле k типа signed int шириной 1 может содержать
только значения -1 и 0, так как битовый шаблон 1 будет интерпретирован как -1.
Примечание
Битовые поля могут быть объявлены только в
структурах, объединениях и классах. Доступ к ним выполняется теми жеселекторами
компонентов (. и ->), что используются для доступа к компонентам других
типов. Кроме того, битовые поля вызывают некоторые проблемы с созданием
переносимых кодов, поскольку организация битов в байтах и байтов в словах
зависит от конкретной машины.
Выражение &mystruct.x недопустимо, так как x это
идентификатор битового поля, а никакой гарантии, что mystruct.x имеет адрес на
границе байта, нет.
Объединения
Объединения соответствуют типам вариантных записей языков Pascal и
Modula-2.
Типы объединений являются производными типами,
разделяющими многие синтаксические и функциональные свойства типов структур.
Главное отличие между ними состоит в том, что объединение позволяет быть
"активным" одновременно только одному компоненту. Размер объединения
равен таким образом размеру своего максимального компонента. Одновременно в
памяти может находиться значение только одного компонента лобъединения. В
следующем простом случае
Страницы: 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
|