C++ - [19]

Шрифт
Интервал

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

int i1 = 256+255; char ch = i1 // ch == 255 int i2 = ch; // i2 == ?

В присваивании ch=i1 теряется один бит (самый значимый!), и ch будет содержать двоичный код «все-единицы» (т.е. 8 единиц); при присваивании i2 это никак не может превратится в 511! Но каким же может быть значение i2? На DEC VAX, где char знаковое, ответ будет -1, на AT amp;T 3B-20, где char беззнаковые, ответ будет 255. В С++ нет динамического (т.е. действующего во время исполнения) механизма для разрешения такого рода проблем, а выяснение на стадии компиляции вообще очень сложно, поэтому программист должен быть внимателен.

2.3.3 Производные Типы

Другие типы можно выводить из основных типов (и типов, определенных пользователем) посредством операций описания:

* указатель amp; ссылка [] вектор () функция

и механизма определения структур. Например:

int* a; float v[10]; char* p[20]; // вектор из 20 указателей на символ void f(int); struct str (* short length; char* p; *);

Правила построения типов с помощью этих операций подробно объясняются в #с.8.3-4. Основная идея состоит в том, что описание производного типа отражает его использование. Например:

int v[10]; // описывает вектор i = v[3]; // использует элемент вектора

int* p; // описывает указатель i = *p; // использует указываемый объект

Вся сложность понимания записи производных типов проистекает из того, что операции * и amp; префиксные, а операции [] () постфиксные, поэтому для формулировки типов в тех случаях, когда приоритеты операций создают затруднения, надо использовать скобки. Например, поскольку приоритет у [] выше, чем у *, то

int* v[10]; // вектор указателей int (*p)[10]; // указатель на вектор

Большинство людей просто помнят, как выглядят наиболее обычные типы.

Описание каждого имени, вводимого в программе, может оказаться утомительным, особенно если их типы одинаковы. Но можно описывать в одном описании несколько имен. В этом случае описание содержит вместо одного имени список имен, разделенных запятыми. Например, два имени можно описать так:

int x, y; // int x; int y;

При описании производных типов можно указать, что операции применяются только к отдельным именам (а не ко всем остальным именам в этом описании). Например:

int* p, y; // int* p; int y; НЕ int* y; int x, *p; // int x; int* p; int v[10], *p; // int v[10]; int* p;

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

2.3.4 Тип void

Тип void (пустой) синтаксически ведет себя как основной тип. Однако использовать его можно только как часть производного типа, объектов типа void не существует. Он используется для того, чтобы указать, что функция не возвращает значения, или как базовый тип для указателей на объекты неизвестного типа.

void f() // f не возвращает значение void* pv; // указатель на объект неизвестного типа

Переменной типа указатель на void (void *), можно присваивать указатель любого типа. На первый взгляд это может показаться не особенно полезным, поскольку void* нельзя разименовать, но именно это ограничение и делает тип void* полезным. Главным образом, он применяется для передачи указателей функциям, которые не позволяют сделать предположение о типе объекта, и для возврата из функций нетипизированных объектов. Чтобы использовать такой объект, необходимо применить явное преобразование типа. Подобные функции обычно находятся на самом нижнем уровне системы, там, где осуществляется работа с основными аппаратными ресурсами. Например:

void* allocate(int size); // выделить void deallocate(void*); // освободить

f() (* int* pi = (int*)allocate(10*sizeof(int)); char* pc = (char*)allocate(10); //... deallocate(pi); deallocate(pc); *)

2.3.5 Указатели

Для большинства типов T T* является типом арифметический указатель на T. То есть, в переменной типа T* может храниться адрес объекта типа T. Для указателей на вектора и указателей на функции вам, к сожалению, придется пользоваться более сложной записью:

int* pi; char** cpp; // указатель на указатель на char int (*vp)[10]; // указатель на вектор из 10 int'ов int (*fp)(char, char*); // указатель на функцию //получающую параметры(char, char*) // и возвращающую int

Основная операция над указателем – разыменование, то есть ссылка на объект, на который указывает указатель. Эта операция также называется косвенным обращением. Операция разыменования – это унарное * (префиксное). Например:

char c1 = 'a'; char* p = amp;c1; // в p хранится адрес c1 char c2 = *p; // c2 = 'a'

Переменная, на которую указывает p,– это c1, а значение, которое хранится в c1, это 'a', поэтому присваиваемое c2 значение *p есть 'a'.

Над указателями можно осуществлять некоторые арифметические действия. Вот, например, функция, подсчитывающая число символов в строке (не считая завершающего 0):


Еще от автора Мюррей Хилл
Справочное руководство по C++

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


Рекомендуем почитать
JavaScript с нуля

JavaScript еще никогда не был так прост! Вы узнаете все возможности языка программирования без общих фраз и неясных терминов. Подробные примеры, иллюстрации и схемы будут понятны даже новичку. Легкая подача информации и живой юмор автора превратят нудное заучивание в занимательную практику по написанию кода. Дойдя до последней главы, вы настолько прокачаете свои навыки, что сможете решить практически любую задачу, будь то простое перемещение элементов на странице или даже собственная браузерная игра.



Язык программирования PHP

PHP, в настоящее время, – один из наиболее популярных языков для реализации веб-приложений. Данный курс посвящен изучению его основ. Акцент делается на практическое применение полученных навыков. Язык PHP был создан для решения конкретной практической задачи в среде интернет (какой именно можно узнать, прочитав первую лекцию курса). Мы тоже постараемся не отвлекаться слишком сильно на теоретические рассуждения, и будем стремиться к решению какой-нибудь конкретной задачи в каждой из лекций. Большинство примеров взяты из реально существующей системы: виртуального музея истории информатики.


Справочник по CSS

Вниманию читателей предлагается справочник по CSS.Справочник предназначается для людей, уже освоивших азы работы с HTML и CSS.Справочник создан на основе информации, предоставленной на сайте «Справочник Web-языков» www.spravkaweb.ru.


Учебник по Delphi 4.0

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


DirectX 8. Начинаем работу с DirectX Graphics

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