16. Типы данных переменных в С. Знаковые и типы данных без знака. Ограничения типов данных переменных
Скачать 220.13 Kb.
|
16. Типы данных переменных в С++. Знаковые и типы данных без знака. Ограничения типов данных переменных. Тип данных — категоризация абстрактного множества возможных значений, характеристик и набор операций для некоторого атрибута Целочисельные типы данных: short int, unsigned short int, int, unsigned int, long, unsigned long. Типы данных с плавающей запятой (соответствуют вещественным типам): float, double, long double. Символьный тип данных: char (signed char), unsigned char, wchar_t. Логический тип данных: bool. Перечислимый тип данных (введен в Visual C++): enum. Тип данных характеризует:
Целый тип данных предназначен для представления в памяти компьютера обычных целых чисел. Основным и наиболее употребительным целым типом является тип int. Гораздо реже используют его разновидности: short (короткое целое) и long (длинное целое). Также к целым типам относится тип char (символьный). Кроме того, при необходимости можно использовать и тип long long (длинное-предлинное!), который хотя и не определён стандартом, но поддерживается многими компиляторами C++. По-умолчанию все целые типы являются знаковыми, т.е. старший бит в таких числах определяет знак числа: 0 — число положительное, 1 — число отрицательное. Кроме знаковых чисел на C++ можно использоватьбеззнаковые. В этом случае все разряды участвуют в формировании целого числа. При описании беззнаковыхцелыхпеременных добавляется слово unsigned (без знака) 17. Константы С++. Способы задания констант. Квалификатор const. Примеры. Константа — это величина, которая при выполнении программы остаётся неизменной. Константа — это ограниченная последовательность символов алфавита языка, представляющая собой изображение фиксированного (неизменяемого) объекта. Константы бывают числовые, символьные и строковые. Числовые константы делятся на целочисленные и вещественные. В С++ для представления константы рекомендуется использовать объявление переменной с начальным значением и ключевым словом const: const тип ИмяПеременной = НачальноеЗначение; const int n=10; Область видимости константы такая же, как у обычной переменной. С помощью ключевого слова constможно объявить указатель на константу const тип *ИмяПеременной; const int *m; // m – указатель на константу типа int const int n=3; m = &n; Еще одна возможность const состоит в создании постоянного указателя на величину указанного типа тип *const ИмяПеременной = Значение; int i; int *const ptri=&i; Использование const имеет несколько преимуществ по сравнению с #define. При объявлении константы с использованием const явно указывается тип величины. Константа, объявленная с использванием const, просто согласуется с производными типами, например, объявление массива: const int base_vals[5] = { 1000, 2000, 3500, 6000, 10000}; Идентификаторы const подчиняются тем же правилам, что и переменные. Можно создавать константы с различной областью видимости. Константы в С++ аналогичны константам в Си. Для представления константы в Си использовалась только директива препроцессора #define Например #define MAX 100 С директивой define препроцессор работает следующим образом. В тексте программы находятся все места, где встречается имя, указанное в директиве define. После этого вместо этого имени подставляется значение, указанное в директиве define. Подстановка значения не производится, если имя встретилось внутри имени переменной, в строке или в комментарии. Так же константой считается число или строка «жестко» задания в коде, например If(a == 1) 1 - константа 18. Выбор целочисленного типа данных. Переполнение целочисленной переменной. Целочисленные константы. Большинство разработчиков на C пишут код для машин, в которых для представления целых чисел используется дополнительный код, а сложение и вычитание в таком представлении реализованы точно так же, в беззнаковой арифметике. Если сумма двух положительных целых чисел со знаком переполнится — то есть станет больше, чем вмещает тип, — процессор выдаст значение, которое, будучи интерпретировано как двоичное дополнение знакового числа, будет считаться отрицательным. Это явление называется «переносом», поскольку результат, дойдя до верхней границы диапазона значений, «переносится» и начинается с нижней границы. при сложении целых может происходить переполнение. Загвоздка в том, что компьютер не выдаёт предупреждения при переполнении: программа продолжит работать с неверными данными. Более того, поведение при переполнении определено только для целых без знака. Переполнение может привести к серьёзным проблемам: обнулению и потере данных, возможным эксплойтам, трудноуловимым ошибкам, которые будут накапливаться с течением времени. Рассмотрим несколько приёмов отслеживания переполнения целых со знаком и переполнения целых без знака. 1. Предварительная проверка данных. Мы знаем, из файла limits.h, максимальное и минимальное значение для чисел типа int. Если оба числа положительные, то их сумма не превысит INT_MAX, если разность INT_MAX и одного из чисел меньше второго числа. Если оба числа отрицательные, то разность INT_MIN и одного из чисел должна быть больше другого. Если же оба числа имеют разные знаки, то однозначно их сумма не превысит INT_MAX или INT_MIN. ?
В этой функции переменной overflow будет присвоено значение 1, если было переполнение. Функция возвращает сумму, независимо от результата сложения. 2. Второй способ проверки – взять для суммы тип, максимальное (и минимальное) значение которого заведомо больше суммы двух целых. После сложения необходимо проверить, чтобы сумма была не больше , чем INT_MAX и не меньше INT_MIN. ?
Обратите внимание на явное приведение типов. Без него сначала произойдёт переполнение, и неправильное число будет записано в переменную c. 3. Третий способ проверки платформозависимый, более того, его реализация будет разной для разных компиляторов. При переполнении целых (обычно) поднимается флаг переполнения в регистре флагов. Можно на ассемблере проверить значение флага сразу же после выполнения суммирования. ?
Здесь переменная noOverflow равна 1, если нет переполнения. jno (jump if no overflow) выполняет переход к метке NO_OVERFLOW, если переполнения не было. Если же переполнение было, то выполняется ?
По адресу переменной noOverflow записывается нуль. Работа с числами без знака гораздо проще: при переполнении происходит обнуление и известно, что получившееся число заведомо будет меньше каждого из слагаемых. ?
Целочисленные константыЦелочисленные данные в языке Си могут быть представлены в одной из следующих систем счисления:
Двоичная система представления данных непосредственно в языке Си не поддерживается. Однако можно воспользоваться файлом binary.h, в котором определены двоичные константы в пределах байта. В зависимости от значения целой константы компилятор присваивает ей тот или иной тип (char, int, long int). С помощью суффикса U (или u) можно представить целую константу в виде беззнакового целого. Например, Константе 200U выделяется 1 байт, и старший бит используется для представления одного из разрядов кода числа и диапазон значений становится от 0 до 255. Суффикс L (или l) позволяет выделить целой константе 8 байт (long int). Совместное использование в любом порядке суффиксов U (или u) и L (или l) позволяет приписать целой константе тип unsigned long int, и она займет в памяти 64 разряда, причем знаковый разряд будет использоваться для представления разряда кода (а не знака). 19. Тип данных «символ». Назначение типа «символ». Система ASCII. Расширенный тип символов. Символ – элементарная единица, некоторый набор которых несет определенный смысл. В языке программирования С++ предусмотрено использование символьных констант. Символьная константа – это целочисленное значение представленное в виде символа, заключённого в одинарные кавычки, например 'a'. В таблице ASCII представлены символы и их целочисленные значения. Строки в С++ представляются как массивы элементов типа char, заканчивающиеся нуль-терминатором \0 называются С строками или строками в стиле С. Char: представляет один символ в кодировке ASCII. Занимает в памяти 1 байт (8 бит). Может хранить любое значение из диапазона от -128 до 127, либо от 0 до 255. ASCII — название таблицы (кодировки, набора), в которой некоторым распространённым печатным и непечатным символам сопоставлены числовые коды. В таблице ASCII, символы с нулевого по 31 включительно, являются управляющими ASCII символами. Это значит, что данные символы выполняют некоторые действия, причём эти символы печатаются с сочетанием клавиши Ctrl. Расширеный тип символов(wchar_t) используется для представления значений расширенных наборов символов, которые соответствуют национальным языкам. В настоящее время стандарт C++ поддерживает следующие типы для представления знаков наборам символов, включая расширенные наборы, как, например, символы UNICODE 20. Тип bool в C++. Способы применения. Размер типа bool в C++. bool — целочисленный тип данных, так как диапазон допустимых значений — целые числа от 0 до 255. Но этологический тип данных. Так как bool используется исключительно для хранения результатов логических выражений. У логического выражения может быть один из двух результатов true или false. true — если логическое выражение истинно, false — если логическое выражение ложно. Но так как диапазон допустимых значений типа данных bool от 0 до 255, то необходимо было как-то сопоставить данный диапазон с определёнными в языке программирования логическими константами true и false. Таким образом, константе true эквивалентны все числа от 1 до 255 включительно, тогда как константе false эквивалентно только одно целое число — 0. Рассмотрим программу с использованием типа данных bool. Почему bool занимает целый байт? Потому что байт - минимальная единица адресации в памяти в языке cи. Тип bool используется для проверки логических условий или как флаг состояний. 21. Числа с плавающей точкой. Типы чисел с плавающей точкой. Константы с плавающей точкой. Есть три типы данных с плавающей точкой: float, double и long double. Как и с целочисленными типами, C++ определяет только их размер.
Float -2 147 483 648.0 / 2 147 483 647.0 long double -9 223 372 036 854 775 808 .0 / 9 223 372 036 854 775 807.0 double -9 223 372 036 854 775 808 .0 / 9 223 372 036 854 775 807.0 Наиболее существенным моментом здесь является то, что способ кодирования, используемый для помещения в память числа с плавающей точкой, полностью отличается от аналогичной схемы для размещения целого числа. Формирование представления числа с плавающей точкой состоит в его разбиении на дробную часть и порядок; затем обе части раздельно помещаются в память. 1. Целые числа не имеют дробной части, в то время как числа с плавающей точкой могут представлять как целые, так и дробные числа. 2. Числа с плавающей точкой дают возможность представлять величины из более широкого диапазона, чем целые (см. табл. 3.1). 3. При некоторых арифметических операциях, например при вычитании одного большого числа из другого, использование чисел с плавающей точкой приводит к большей потере точности. 4. Операции над числами с плавающей точкой выполняются, как правило, медленнее, чем операции над целыми числами. Однако сейчас уже появились микропроцессоры, специально ориентированные на обработку чисел с плавающей точкой, и в них эти операции выполняются довольно быстро. Правила языка Си допускают несколько способов записи констант с плавающей точкой. Наиболее общая форма записи константы - это последовательность десятичных цифр со знаком, включающая в себя десятичную точку, затем символ е или Е и показатель степени по основанию 10 со знаком. Вот два примера: -1.56Е+12 2.87е-3 Знак + можно не писать. Разрешается также опускать либо десятичную точку, либо экспоненциальную часть, но не одновременно. Кроме того, можно не писать дробную или целую часть, но не обе сразу. Использовать пробелы при записи констант запрещается some = 4.0*2.0; В этом случае константы 4.0 и 2.0 размещаются в памяти как данные типа double, т. е. для каждой из них (обычно) отводится 64 бит. Их произведение (равное 8) вычисляется с помощью операции умножения, выполняемой с двойной точностью, и только после этого производится усечение результата до нормального размера, соответствующего типу float. Все это обеспечивает максимальную точность вычислений. 22. Арифметические операции в C++. Преобразования типов при выполнении арифметических операций. + — сложение; - — вычитание; * — умножение; / — деление; % — остаток от деления. Различают унарные операторы и бинарные Унарные операторы – это те, которые применяются только к одному операнду (x++, x--) Унарные операторы могут быть записаны в 2х формах : x++ или ++x Различие заключается в последовательности обработки, например Print(x++) выведет значение x, а затем инкрементирует его Print(++x) сначала инкрементирует x, а затем выведет Бинарные операторы – это те, которые применяются к двум операндам (слева и справа), они описаны выше Арифметические операции можно применять для: целочисленных типов: short int, unsigned short int, int, unsigned int, long, unsigned long; типов с плавающей запятой (вещественных типов): float, double, long double; типов (классов), которые содержат «перегруженные» арифметические операции. В выражениях, где используются операции +, —, *, действуют следующие правила приведения типа результата: если оба операнда имеют целый тип, то результат также будет целого типа; если хотя бы один из операндов имеет вещественный (с плавающей запятой) тип а другой целый тип, то результат также будет вещественного типа; если один из операндов имеет тип float, а другой тип double, то результат будет типа double. Это связано с тем, что тип double требует больше памяти чем тип float. В этом случае происходит расширение типа float к типу double. Операция деления имеет свои особенности, которые состоят в следующем: если два операнда имеют целочисленный тип, то результат возвращается целого типа. В этом случае происходит деление нацело. Остаток от деления урезается; если один из операндов имеет тип с плавающей запятой, тогда результат имеет также тип с плавающей запятой. 23. Преобразование типов С++ при инициализации и присваивании. Преобразование типов С++ в выражениях. Преобразование типов С++ при передаче аргументов. Преобразование типов предназначено для ситуации, в которой переменные одного типа смешиваются с переменными другого типа. Когда возникает подобная ситуация в операторе присваивания, используется правило преобразования типов: значение справа (выражение) от оператора присваивания преобразуется к типу объекта, стоящего слева (целевой переменной). Когда происходит преобразование из целого числа к символу, из длинного целого — к целому и из целого — к короткому целому, то старшие биты будут потеряны. Когда используется 16-битное целое, это означает, что 8 бит будут потеряны при преобразовании от целого к символу и 16 бит будут потеряны при преобразовании от длинного целого к целому.
Для получения преобразования, не указанного в таблице, надо просто пошагово преобразовывать типы, пока не получится нужный тип. Например, для преобразования из double в int сначала следует преобразовать double в float, а затем float в int. 24. Явное и неявное преобразование типов. Операции приведения типов. Преобразование значения переменной одного типа в значение другого типа называется приведение типа (через букву "е") и бывает явными неявным:
ПРИМЕР ЯВНОГО ПРИВЕДЕНИЯ ТИПАint x = 5; double y = 15.3; x = (int) y; y = (double) x; ПРИМЕР НЕЯВНОГО ПРИВЕДЕНИЯ ТИПАint x = 5; double y = 15.3; y = x; //здесь происходит неявное приведение типа к double x = y; //здесь происходит неявное приведение типа к int НЕЯВНОЕ ПРИВЕДЕНИЕ ТИПА ПРИ АРИФМЕТИЧЕСКИХ ОПЕРАЦИЯХ
Заметим, что в последнем случае (и только в нем) осуществляется целочисленное деление с отбрасыванием остатка. |