Архивы рубрики: Операционные системы

Исходные файлы С++

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

extern double sqrt(double);
extern instream cin;

Самый простой способ обеспечить согласованность исходных файлов — помещение таких же описаний в отдельные файлы, которые называются заголовочными (или хэдер) файлами, после чего включить, т. е. скопировать, эти заголовочные файлы во все файлы, где необхо-
димы эти описания. К примеру, если описание sqrt располагается в заголовочном файле для стандартных математических функций math.h и необходимо извлечь квадратный корень из 4, следует применить программу:

#include
—…
x = sqrt(4);

Так как обычные заголовочные файлы состоят из большого числа исходных файлов, в них нет описаний, которые не должны повторяться.
В команде включения include имя файла, которое располагается в угловых скобках, например, относится к файлу с таким именем в стандартном каталоге (обычно это -usr-include-CC); на файлы, хранящиеся в других местах, ссылаются, применяя имена, расположенные в двойных кавычках. Например:

#include «math1.h»
#include «-usr-bs-math2.h»

включит math1.h из текущего пользовательского каталога, а math2.h из каталога -usr-bs.

Покажем, как мы могли бы определить тип потока вывода ostream. Для упрощения задачи предположим, что для буферизации определен тип streambuf. Тип streambuf определен в том месте, где также располагается и настоящее определение ostream. Значение типа, определяемого пользователем, специфицирует данные, которые нужны для представления объекта этого типа, и большое число операций для работы
с этими объектами. Определение состоит из двух частей: закрытой (private) части, в которой находится информация, используемая только его разработчиком, и открытой (public) части, являющейся интерфейсом типа с пользователем.

 

Описание функций в языке Си

При использовании операции ++ к целой переменной к ней просто добавляется единица. Первая часть оператора for не обязательно должна быть описанием, она может быть простым оператором. К примеру:

for (i=0; i<10; i++) q[i]=»p[i];» тоже по смыслу соответствует предыдущей записи при условии, что i соответствующим образом описано раньше.
Описание представляет собой оператор, который вводит имя в программе. Оно способно и инициализировать объект с этим именем. Выполнение описания значит, что при достижении потоком управления описания вычисляется инициализирующее выражение (инициализатор) и наблюдалась инициализация.

Например:

for (int i = 1; i

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

extern float pow(float, int); —pow()
main()
{
for (int i=0; i<10; i++) cout << pow(2,i) << «\n»; } Первая строка функции — описание, которое указывает, что pow — функция, которая получает параметры типа float и int и возвращает float. Описание функции применяется для выполнения определенных обращений к функции в других местах. При вызове тип любого параметра функции сопоставляется с ожидаемым типом аналогично тому, как если бы инициализировалась переменная приведенного типа. Это дает га-
рантии надлежащей проверки и преобразования типов.

К примеру, обращение pow (12.3, «abcd») вызовет недовольство компилятора, так как «abcd» является строкой, а не int. В случае вызова (2,i) компилятор преобразует 2 к типу float, т. е. требуется функция. Функция pow может быть определена, к примеру, следующим образом:
float pow(float x, int n)
{
if (n < 0) error(«извините, отрицательный показатель для pow()»); switch(n) {case 0: return 1; case 1: return x; default: return x*pow(x,n–1);}}

 

Оператор switch, break. Копирование строки в Си

Оператор switch дает возможность сопоставления значения с множеством констант. Проверки в предыдущем примере можно представить в следующем виде:

switch (ch) {
case ‘i’:
in = x;
cm = x*fac;
break;
case ‘c’:
in = x-fac;
cm = x;
break;
default:
in = cm = 0;
break;
}

Операторы break используются для выхода из оператора switch. Константы в вариантах case могут иметь различные значения, и если проверяемое значение не совпадает ни с одной из констант, принимается вариант default. Программист не обязательно должен предусматривать default.

Покажем копирование строки, когда заданы указатель p на ее первый символ и указатель q на целевую строку. По соглашению строка заканчивается символом с целым значением 0.

while (p != 0) {
*q = *p; — скопировать символ
q = q+1;
p = p+1;
}
*q = 0; — завершающий символ 0 скопирован не
был.
После while любое условие должно находиться в круглых скобках. Условие вычисляется, и, если оно не нулевое, выполняется непосредственно следующий за ним оператор. Это происходит до тех пор, пока вычисление условия не даст ноль. Можно применять операцию ++ для непосредственного указания увеличения, и проверка будет значительно проще:

while (*p) *q++ = *p++;
*q = 0;
где конструкция *p++ значит: «взять символ, на который задает p, затем увеличить p».

 

Оператор выражение. Пустой оператор в Си

Самый простой вид оператора в языке Си — оператор выражение. Он включает в себя выражение, за которым следует точка с запятой.
К примеру:

a = b*3 + c;
cout << «go go go»; lseek(fd,0,2); Простейший оператор — пустой оператор:

;

Он не делает ничего. Но он используется тогда, когда синтаксис требует присутствия оператора, а данный оператор не нужен.
Блок представляет собой возможно пустой список операторов, находящихся в фигурных скобках:
{a = b + 2; b++;}

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

#include
main()
{
const float fac = 2.54;
float x, in, cm;
char ch = 0;
cout x >> ch;
if (ch == ‘i’) { — inch — дюймы
in = x;
cm = x*fac;
}
else if (ch == ‘c’) — cm — сантиметры
in = x-fac;
cm = x;
}
else
in = cm = 0;
cout << in << « in=» << cm << « cm\n»;}

 

Операции языка СИ++

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

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

Таблица 1

Операции, применяемые к целым операндам

Смысл операции определяется числом операндов;
унарное & — операция взятия адреса, а бинарное & — операция логического И.

Смысл операции определяется также типом ее операндов: + в выражении a + b означает сложение с плавающей точкой, если тип операндов float, но целое сложение, если их тип int. В C++ существует операция присваивания =, а не оператор при-сваивания, как в некоторых
языках. То есть присваивание может употребляться в неожиданном контексте; например, x = sqrt(a = 3*x).

Выражение a = b = c значит присвоение c объекту b, а потом объекту a. Другое свойство операции присваивания — она способна совмещаться с большинством бинарных операций. К примеру, x[i + 3]* = 4 имеет значение x[i + 3] = x[i + 3]*4, за исключением того, что выражение x[i + 3] определяется только один раз. Это дает большую степень эффективности без необходимости употребления оптимизирующего компилятора. К тому же это менее длинно. Во многих программах на C++ широко используются указатели.

Унарная операция * разыменовывает указатель, т. е. *p представляет собой объект, на который указывает p. Данная операция также именуется косвенной адресацией. Например, если имеется char* p, то *p — это символ, на который указывает p. Часто при работе с указателями применяются операция увеличения ++ и операция уменьшения —.

 

Соотношение между основными типами данных в СИ++

Соотношение между основными типами можно представить так:

1 = sizeof(char) <= sizeof(short) <=«sizeof(int)»
<=«sizeof(long)» sizeof(float) <=«sizeof(double)» В итоге предполагать что-то еще относительно основных типов неразумно. Например, то, что целое достаточно для хранения указателя, справедливо не для всех машин. В основном типе можно использовать прилагательное const. Это дает тип, который имеет те же свой-
ства, что и первоначальный тип, за исключением того, что значение переменных типа const не может меняться после инициализации.

const float pi = 3.14;
const char plus = ‘+’;

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

К каждой комбинации данных типов могут применяться арифметические операции: + (плюс, унарный и бинарный), – (минус, унарный и бинарный), * (умножение), — (деление). Кроме этого применяются операции сравнения: = (равно), != (не равно), (больше), = (больше или равно).

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

double d = 1;
int i = 1;
d = d + i;
i = d + i;

Рассмотрим операции, которые создают из основных типов новые типы: * (указатель на), *const (константный указатель на), & (ссылка на), [] (вектор), () (функция, возвращающая).

У всех векторов нижней границей индекса является ноль, поэтому в v десять элементов: v[0] … v[9].

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

char c;
— …
p = &c — p указывает на c
Унарное & — операция взятия адреса.