Пожалуйста, приостановите работу AdBlock на этом сайте.
Чтобы хранить в своей программе какие-либо данные, вам понадобятся переменные. Прежде всего, нужно научиться эти переменные в программе создавать. Другими словами, вспоминая нашу аналогию с коробками, чтобы в коробку что-то положить, её, эту самую коробку, хорошо бы сначала где-нибудь раздобыть.
В книжках по программированию процесс создания переменной называют объявлением переменной . Это словосочетание хорошо бы знать, чтобы понимать профессиональную литературу и речь других программистов. Но ещё более важно понимать, что за этим словосочетанием скрывается.
Как объявить переменную?
Для того чтобы объявить переменную, необходимо указать её тип и записать её имя. Ну и не забыть поставить ";". Общая стуктура объявления переменной показана на следующем рисунке.
Рис.1. Общий синтаксис объявления переменной.".
В примере на рисунке мы создаём переменную с именем num, в которой можно будет хранить целые числа. На то, что мы собираемся использовать переменную для хранения целых чисел, указывает тип данных int.
Ещё парочка примеров:
Листинг 1. Объявление переменных
Int z; // переменная z целого типа char w; // переменная w символьного типа
Для имён переменных есть одно правило, которое надо будет запомнить.
В качестве имени переменной может выступать любая последовательность символов латинского алфавита, цифр и знака нижнего подчеркивания "_", которая начинается с буквы.
На самом деле, на имя переменной есть дополнительные ограничения, но мы пока в такие детали вдаваться не будем. Давайте лучше посмотрим на примеры правильных и неправильных имён.
Правильные имена переменных
Peremennaya, flag, f3, var4, KolichestvoBukv, fd4s, FLaG, key_number
Неправильные имена переменных
2num – начинается с цифры
num flat – содержит пробел в имени
nomer-telefona – содержит дефис
И ещё один важный момент. В языке программирования Си регистр букв очень важен. Например, переменные с именами flag, FLAG, FlAg, fLAg -- это всё различные переменные. Кроме того, есть ряд слов, которые нельзя использовать для названия переменных. Например, int, void, return и другие. Это специальные ключевые слова , которые зарезервированы для нужд самого языка и нигде в другом месте не могу быть использованы.
Кстати, за одно объявление можно создать сразу несколько переменных одного типа.
Листинг 2. Объявление нескольких переменных
Int a,c; // объявляем переменные a и c целого типа double x, y, z; // объявляем сразу три вещественные переменные
Всё просто и логично. Сначала указывает тип переменных, а потом их имена, разделённые запятой.
Переменная в памяти компьютера.
Пару слов о том, как выглядит объявление переменной с точки зрения компьютера.
Можно считать, что при объявлении мы сообщаем компьютеру, чтобы он выделил под переменную место в памяти и связал это место определенным именем. Количество места, которое будет выделено в памяти для хранения переменной, зависит от типа этой переменной. Проиллюстрируем эту мысль следующим рисунком.
Листинг 3. Объявление двух переменных
Int w; // объявляем целочисленной переменной w double z; // объявляем вещественной переменной z
Рис.3. Переменные в памяти компьютера.
На рисунке условно изображена память компьютера как набор ячеек, в каждой из которых может что-то храниться. При этом вещественная переменная занимает две ячейки, а целочисленная всего одну. Это соотношение (два к одному) условное. На самом деле, в вашем компьютере переменная вещественного типа может занимать, например, в четыре раза больше места в памяти, чем целочисленная переменная.
Практика
Решите предложенные задачи: Для удобства работы сразу переходите в полноэкранный режим
Исследовательские задачи для хакеров
- Объявите в программе переменную с неправильным именем и попробуйте скомпилировать программу. Посмотрите, какую ошибку выдаст компилятор.
- Найдите список всех ключевых слов языка Си. Можно искать в стандарте языка(подсказка: "keywords"), а можно в интернете. Запоминать наизусть их не нужно, но разок посмотреть на них стоит.
Кроме разделения данных на переменные и константы, существует классификация данных по типу. Описание переменных прежде всего состоит в объявлении их типа. Тип данных характеризует область их значений и форму представления в памяти компьютера. Каждый тип характеризуется набором выполняемых над данными операций. Традиционно в универсальных языках программирования существуют такие стандартные типы, как целый, вещественный, символьный и логический 3 . Сразу отметим, что логического типа в Си нет. Выражение (в частном случае, переменная) считается истинным, если оно отлично от нуля, в противном случае оно считается ложным.
Существование двух числовых типов (целого и вещественного) связано с двумя возможными формами представления чисел в памяти компьютера.
Данные целого типа хранятся в форме представленияс фиксированной точкой . Для нее характерны абсолютная точность представления чисел и выполнения операций над ними, а также ограниченный диапазон значений чисел. Целый тип используется для данных, которые в принципе не могут иметь дробной части (количество людей, машин, и т.д., номера и счетчики).
Тип вещественный соответствует форме представления чиселс плавающей точкой , для которой характерны приближенное представление числа с заданным количеством значащих цифр (знаков мантиссы) и большим диапазоном порядка числа, что обеспечивает возможность представления как очень больших, так и очень малых по абсолютной величине чисел. В силу приближенного представления данных вещественного типа ихнекорректно сравнивать на равенство .
В современных реализациях универсальных языков программирования обычно существует несколько целых и несколько вещественных типов, каждый их которых характеризуется своим размером отводимой под одно значение памяти и, соответственно, своим диапазоном значений чисел, а для вещественных типов - и своей точностью (числом цифр мантиссы).
Данные символьного типа принимают значения на всем множестве допустимых для данного компьютера символов. Для хранения одного символьного значения отводится один байт, кодирование символов осуществляется в соответствии со стандартной таблицей кодирования (обычноASCII).
В Си имеется 4 базовых типа:
char - символьный тип;
int - целый тип,
float - вещественный тип одинарной точности,
double - вещественный тип двойной точности.
Для задания производных типов используются квалификаторы :short (короткий) - используется с типомint ,long (длинный) - используется с типамиint иdouble ;signed (со знаком),unsigned (без знака) - применимы к любому целому типу. При отсутствии словаunsignedзначение считается знаковым,т. е. по умолчанию принятоsigned. В силу допустимости произвольного соединения квалификаторов и названий базовых типов один тип может иметь несколько обозначений. Сведения о стандартных типах Си представлены в таблицах 1 и 2. Через запятую в клетках первого столбца перечислены описатели-синонимы.
Таблица 1. Стандартные целые типы данных Си
Тип данных |
Диапазон значений |
|
char, signed char | ||
unsigned int, unsigned | ||
int, signed int, short int, short | ||
2147483648...2147483647 |
Интересно, что в Си тип charв зависимости от контекста может использоваться как символьный или как целый тип.
Таблица 2. Стандартные вещественные типы данных Си
Замечание. Для написания программ первой части пособия нам потребуются в основномдва типа: float и int .
Последнее обновление: 17.09.2017
Каждая переменная имеет определенный тип. И этот тип определяет, какие значения может иметь переменная, какие операции с ней можно производить и сколько байт в памяти она будет занимать. В языке C++ определены следующие базовые типы данных:
bool : логический тип. Может принимать одну из двух значений true (истина) и false (ложь). Размер занимаемой памяти для этого типа точно не определен.
char : представляет один символ в кодировке ASCII. Занимает в памяти 1 байт (8 бит). Может хранить любое значение из диапазона от -128 до 127, либо от 0 до 255
signed char : представляет один символ. Занимает в памяти 1 байт (8 бит). Может хранить любой значение из диапазона от -128 до 127
unsigned char : представляет один символ. Занимает в памяти 1 байт (8 бит). Может хранить любой значение из диапазона от 0 до 255
wchar_t : представляет расширенный символ. На Windows занимает в памяти 2 байта (16 бит), на Linux - 4 байта (32 бита). Может хранить любой значение из диапазона от 0 до 65 535 (при 2 байтах), либо от 0 до 4 294 967 295 (для 4 байт)
char16_t : представляет один символ в кодировке Unicode. Занимает в памяти 2 байта (16 бит). Может хранить любой значение из диапазона от 0 до 65 535
char32_t : представляет один символ в кодировке Unicode. Занимает в памяти 4 байта (32 бита). Может хранить любой значение из диапазона от 0 до 4 294 967 295
short : представляет целое число в диапазоне от –32768 до 32767. Занимает в памяти 2 байта (16 бит).
Данный тип также имеет синонимы short int , signed short int , signed short .
unsigned short : представляет целое число в диапазоне от 0 до 65535. Занимает в памяти 2 байта (16 бит).
Данный тип также имеет синоним unsigned short int .
int : представляет целое число. В зависимости от архитектуры процессора может занимать 2 байта (16 бит) или 4 байта (32 бита). Диапазон предельных значений соответственно также может варьироваться от –32768 до 32767 (при 2 байтах) или от −2 147 483 648 до 2 147 483 647 (при 4 байтах). Но в любом случае размер должен быть больше или равен размеру типа short и меньше или равен размеру типа long
Данный тип имеет синонимы signed int и signed .
unsigned int : представляет положительное целое число. В зависимости от архитектуры процессора может занимать 2 байта (16 бит) или 4 байта (32 бита), и из-за этого диапазон предельных значений может меняться: от 0 до 65535 (для 2 байт), либо от 0 до 4 294 967 295 (для 4 байт).
В качестве синонима этого типа может использоваться unsigned
long : представляет целое число в диапазоне от −2 147 483 648 до 2 147 483 647. Занимает в памяти 4 байта (32 бита).
У данного типа также есть синонимы long int , signed long int и signed long
unsigned long : представляет целое число в диапазоне от 0 до 4 294 967 295. Занимает в памяти 4 байта (32 бита).
Имеет синоним unsigned long int .
long long : представляет целое число в диапазоне от −9 223 372 036 854 775 808 до +9 223 372 036 854 775 807. Занимает в памяти, как правило, 8 байт (64 бита).
Имеет синонимы long long int , signed long long int и signed long long .
unsigned long long : представляет целое число в диапазоне от 0 до 18 446 744 073 709 551 615. Занимает в памяти, как правило, 8 байт (64 бита).
Имеет синоним unsigned long long int .
float : представляет вещественное число ординарной точности с плавающей точкой в диапазоне +/- 3.4E-38 до 3.4E+38. В памяти занимает 4 байта (32 бита)
double : представляет вещественное число двойной точности с плавающей точкой в диапазоне +/- 1.7E-308 до 1.7E+308. В памяти занимает 8 байт (64 бита)
long double : представляет вещественное число двойной точности с плавающей точкой не менее 8 байт (64 бит). В зависимости от размера занимаемой памяти может отличаться диапазон допустимых значений.
void : тип без значения
Таким образом, все типы данных за исключением void могут быть разделены на три группы: символьные (char, wchar_t, char16_t, char32_t), целочисленные (short, int, long, long long) и типы чисел с плавающей точкой (float, double, long double).
Символьные типы
Для представления символов в приложении используются типы char , wchar_t , char16_t и char32_t .
Определим несколько переменных:
Char c ="d"; wchar_t d ="c";
Переменная типа char в качестве значения принимает один символ в одинарных кавычках: char c ="d" . Также можно присвоить число из указанного выше в списке диапазона: char c = 120 . В этом случае значением переменной c будет тот символ, который имеет код 120 в таблице символов ASCII.
Стоит учитывать, что для вывода на консоль символов wchar_t следует использовать не std::cout, а поток std::wcout :
#include
При этом поток std::wcout может работать как с char, так и с wchar_t. А поток std::cout для переменной wchar_t вместо символа будет выводить его числовой код.
В стандарте С++11 были добавлены типы char16_t и char32_t , которые ориентированы на использование Unicode. Однако на уровне ОС пока не реализованы потоки для работы с этими типами. Поэтому если потребуется вывести на консоль значения переменных этих типов, то необходимо преобразовать переменные к типам char или wchar_t:
#include
В данном случае при выводе перед переменными указывается операция приведения к типу char - (char) , благодаря чему значения переменных b, c и d преобразуются в тип char и могут быть выведены на консоль с помощью потока std::cout.
Целочисленные типы
Целочисленные типы представлены следующими типами: short , unsigned short , int , unsigned int , long , unsigned long , long long и unsigned long long :
Short a = -10; unsigned short b= 10; int c = -30; unsigned int d = 60; long e = -170; unsigned long f = 45; long long g = 89;
Типы чисел с плавающей точкой
Типы чисел с плавающей точкой иили дробные числа представлены такими типами как float , double и long double :
Float a = -10.45; double b = 0.00105; long double c = 30.890045;
Размеры типов данных
В выше приведенном списке для каждого типа указан размер, который он занимает в памяти. Однако стоит отметить, что предельные размеры для типов разработчики компиляторов могут выбирать самостоятельно, исходя из аппаратных возможностей компьютера. Стандарт устанавливает лишь минимальные значения, которые должны быть. Например, для типов int и short минимальное значение - 16 бит, для типа long - 32 бита, для типа long double. При этом размер типа long должен быть не меньше размера типа int, а размер типа int - не меньше размера типа short, а размер типа long double должен быть больше double. К примеру, компилятор g++ под Windows для long double использует 12 байт, а компилятор, встроенный в Visual Studio и также работающий под Windows, для long double использует 8 байт. То есть даже в рамках одной платформы разные компиляторы могут по разному подходить к размерам некоторых типов данных. Но в целом используются те размеры, которые указаны выше при описании типов данных.
Однако бывают ситуации, когда необходимо точно знать размер определенного типа. И для этого в С++ есть оператор sizeof() , который возвращает размер памяти в байтах, которую занимает переменная:
#include
Консольный вывод при компиляции в g++:
sizeof(number) = 12
При этом при определении переменных важно понимать, что значение переменной не должно выходить за те пределы, которые очерчены для ее типа. Например:
Unsigned short number = -65535;
Компилятор G++ при компиляции программы с этой строкой выдаст ошибку о том, что значение -65535 не входит в диапазон допустимых значений для типа unsigned short и будет усечено.
В Visual Studio компиляция может пройти без ошибок, однако при этом переменная number получит значение 2 - результат преобразования числа -65535 к типу unsigned short. То есть опять же результат будет не совсем тот, который ожидается. Значение переменной - это всего лишь набор битов в памяти, которые интерпретируются в соответствии с определенным типом. И для разных типов один и тот же набор битов может интерпретироваться по разному. Поэтому важно учитывать диапазоны значений для того или иного типа при присвоении переменной значения.
Спецификатор auto
Иногда бывает трудно определить тип выражения. И согласно последним стандартам можно предоставить компилятору самому выводить тип объекта. И для этого применяется спецификатор auto . При этом если мы определяем переменную со спецификатором auto, эта переменная должна быть обязательно инициализирована каким-либо значением:
Auto number = 5;
На основании присвоенного значения компилятор выведет тип переменной. Неинициализированные переменные со спецификатором auto не допускаются.
Тип данных – это описание диапазона значений, которые может принимать переменная, указанного типа. Каждый тип данных характеризуется:1. количеством занимаемых байт(размером)
2. диапазоном значений которые может принимать переменная данного типа.
Все типы данных можно разделить на следующие виды:
1. простые (скалярные) и сложные (векторные) типы;
2. базовые (системные) и пользовательские(которые определил пользователь).
В языке СИ систему базовых типов образуют четыре типа данных:
1. символьный,
2. целочисленный,
3. вещественный одинарной точности,
4. вещественный двойной точности.
Подробное описание типов данных в языке СИ
тип | Символьный тип | Целочисленный тип | Вещественный тип одинарной точности | Вещественный тип двойной точности |
описание | char | int | float | double |
размер | 1 байт (8 бит) | 4 байта (32 бита) | 4 байта (32 бита) 23 бита – мантисса; 8 бит – порядок; 1 бит – знак. |
8 байт (64 бита) 52 бита – мантисса; 11 бит – порядок; 1 бит – знак. |
диапазон значений | -128 ... 127 | 2147483648 ... 2147483647 | ±3.4Е±38 Точность до 7 знаков после запятой |
±1.7Е±308 Точность до 17 знаков после запятой |
В языке СИ предусмотрены модификаторы типов данных двух видов:
1. модификаторы знака: signed и unsigned.
2. модификаторы размера: short и long.
Более подробно модификаторы типов описаны в таблице:
Комплексные числа в СИ
Комплексные числа введены в стандарте C99. float _Complex
double _Complex
long double _Complex
Все это счастье находиться в библиотеке complex.h :)
Минимальные и максимальные значения всех базовых типов данных языка СИ описаны в библиотеках: limits.h – содержит диапазоны целочисленных значений, float.h – содержит диапазоны вещественных значений.
Логический тип данных в СИ
Стандарт С89:
Логический тип – int
0 – ложь (false);
не 0 – истина (true). Т.е как такового логического типа не создано, а вместо него используется int.
Стандарт С99:
Логический тип - _Bool
Ключевые слова: bool true false
А это счастье в библиотеке stdbool.h
Операторы объявлений
Переменная – именованная область памяти вычислительной машины, предназначенная для хранения значений определенного типа, с
произвольным методом доступа: чтение и запись. Имя переменой – разрешенный идентификатор языка СИ не использовавшийся ранее для
обозначения других переменных, типов, элементов перечислений или имен функций. Оператор объявления переменных имеет следующий
синтаксис: тип имя1[,имя2[,...]]; Примеры: int a, b, c;
double x, y;
char ch; Есть некоторые негласные правила, т.е исполнения который является хорошим тоном, но делать это не обязательно:
1. каждое объявление переменных нового типа начинается с новой строки;
2. из названия переменной должно быть понятно зачем она и что в ней будет храниться(хотя иногда из-за таких вот информативных названий скорость написания кода падает, т.к некоторых заносит и они называют переменные целыми предложениями);
3. поэтому появляется правило: название переменной не должно быть слишком длинным;
4. после объявления переменной очень желательно в комментариях пометить зачем она;
5. необходимо разделять имена переменных пробелами.
Оператор объявления переменных с инициализацией имеет следующий синтаксис: тип имя1[=значение1][, имя2[=значение2][,...]]; Примеры:
int a=26, b=032, c=0x1A;
double x=2.5e2,y=0x1.ffe-3;
char ch=’Z’;
Константы в СИ
В языке СИ присутствует три вида констант:1. целочисленные,
2. вещественные,
3. символьные.
Целочисленные константы
1. Десятичная константа указывается десятичным числом в обычной форме.
2. Восьмеричная константа указывается числом, начинающимся с цифры ноль и содержащим цифры 0...7.
3. Шестнадцатеричная константа указывается целым числом с префиксом 0x или 0X, содержащим цифры 0...9 и буквы латинского алфавита a...f, A...F.
Вещественные константы записываются в десятичной или шестнадцатеричной системе исчисления. Позиция запятой указывается точкой, экспонента указывается после латинской буквы e (или E). Символьным константам предшествует символ \, это так называемое "экранирование" . В языке СИ присутствуют специальные символы:
‘\’’ – одинарная кавычка,
‘\”’ – двойная кавычка,
‘\\’ – обратный слеш,
‘\?’ – знак вопроса,
‘\a’ – звуковой сигнал,
‘\b’ – удаление символа,
‘\f’ – прокрутка страницы,
‘\n’ – перевод строки,
‘\r’ – возврат каретки в начало строки,
‘\t’ – горизонтальная табуляция,
‘\v’ – вертикальная табуляция.
В языке СИ можно также создавать переменные, имеющие константное значение (их значение нельзя изменить). Объявление таких
«переменных» имеет следующий синтаксис: const тип имя1=значение1[,имя2=значение2[,...]]; Примеры:
const unsigned int x=80, y=25;
const double pi=3.1415;
Оператор создания типов данных в СИ
Оператор typedef используется для создания пользовательских типов данных, синтаксис его использования: typedef имя_старого_типа
имя_нового_типа; Пример: typedef unsigned int word;
В СИ согласно стандарту, определение типов может производиться практически в любом месте программы(т.е нет строго определенного блока для определения типов данных).Функция для определения размера типа, или переменной какого-либо типа: sizeof, она возвращает количество занимаемых байт в памяти. Пример:
sizeof(int) //вернет 4
sizeof(char) //результат 1
sizeof(double) // вернет 8
Все данные в языке Си имеют свой тип. Переменные определенных типов занимают в памяти какое-то место, разное в зависимости от типа. В Си нет четкого закрепления количества памяти за определенными типами. Это отдано на реализацию конкретного компилятора под конкретную платформу. Например, переменная типа int в одном компиляторе может занимать в памяти 16 бит, в другом — 32 бита, в третьем — 8 бит. Все определяет конкретный компилятор. Правда, все стремятся к универсализации, и в основном в большинстве компиляторов тип int , например, занимает 2 байта, а тип char — один.
Я в последнее время немного затупил, не мог вспомнить, сколько байт занимает тип double в AVR-GCC . Обычно при программировании контроллеров работаешь с целочисленными типами, типа int и char , а к типам с плавающей точкой прибегаешь не часто, в связи с их ресурсоемкостью.
Поэтому, на будущее, оставлю себе здесь памятку с указанием размеров занимаемой памяти типами данных для компилятора AVR-GCC и диапазон изменения переменных этого типа.
Типы данных в языке Си для компилятора AVR-GCC
Тип | Размер в байтах (битах) |
Интервал изменения |
---|---|---|
char | 1 (8) | -128 .. 127 |
unsigned char | 1 (8) | 0 .. 255 |
signed char | 1 (8) | -128 .. 127 |
int | 2 (16) | -32768 .. 32767 |
unsigned int | 2 (16) | 0 .. 65535 |
signed int | 2 (16) | -32768 .. 32767 |
short int | 2 (16) | -32768 .. 32767 |
unsigned short int | 2 (16) | 0 .. 65535 |
signed short int | 2 (16) | -32768 .. 32767 |
long int | 4 (32) | -2147483648 .. 2147483647 |
unsigned long int | 4 (32) | 0 .. 4294967295 |
signed long int | 4 (32) | -2147483648 .. 2147483647 |
float | 4 (32) | 3.4Е-38 .. 3.4Е+38 |
double | 4 (32) | 3.4Е-38 .. 3.4Е+38 |
long double | 10 (80) | 3.4Е-4932 .. 3.4Е+4932 |
Обратите внимание
Реализация типа double в AVR-GCC отступает от стандарта. По стандарту double занимает 64 бита. В AVR-GCC переменная этого типа занимает 32 бита, и соответственно, она эквивалентна переменной с типом float !
В дополнение к этому, в библиотеках AVR-GCC введено несколько производных от стандартных типов. Они описаны в файле stdint.h . Сделано это, наверно, для улучшения наглядности и уменьшения текста программ (ускорения их написания:)). Вот табличка соответствия:
Производные типы от стандартных в языке Си для компилятора AVR-GCC
Производный тип | Стандартный тип |
---|---|
int8_t | signed char |
uint8_t | unsigned char |
int16_t | signed int |
uint16_t | unsigned int |
int32_t | signed long int |
uint32_t | unsigned long int |
int64_t | signed long long int |
uint64_t | unsigned long long int |
Тип Void
В языке Си есть еще один тип — тип void . Void используется для указания, что функция не возвращает ничего в качестве результата, или не принимает на вход никаких параметров. Этот тип не применяется для объявления переменных, соответственно он не занимает места в памяти.