Типы данных языка Си
Переменные
Чтобы прочитать данные из памяти или записать даные в память необходимо знать адреса ячеек с которыми будут осуществляться действия. Так как различных данных у программ, включая промежуточные значения вычислений, огромное количество, то запомнить адреса ячеек практически не возможно. Поэтому для работы с данными используются переменные.
Переменная - это ячейка в памяти, которая имеет имя, адрес в памяти и значение. Значение может меняться в процессе выполнения программы путем записи нового значения вместо старого.
Имена переменных могут начинаться с латинской буквы или символа подчеркивания и могут содержать только латинские буквы, цифры или символ подчеркивания.
Типы данных
Язык программирования Си является строго типизированным. А это значит, что при объявлении переменной необходимо объявить ее тип, под который будет выделено нужное количество памяти и который будет неизменным все время работы программы. Типы данных различаются диапазонами возможных значений и требуют для хранения разное количество байт. Это следует учитывать при разработке приложений, особенно при написании программ для контроллеров, которые обладают ограниченными размерами памяти. В таблице ниже перечислены все типы языка Си.
Название типа | Размер памяти | Диапазон значений | Псевдонимы |
---|---|---|---|
char | 1 байт | 1 символ | |
unsigned char | 1 байт | от 0 до 255 | |
signed char | 1 байт | от -128 до 127 | |
short | 2 байта | от 32768 до 32767 | short int, signed short, signed short int |
unsigned short | 2 байта | от 0 до 65535 | unsigned short int |
int | 2 или 4 байта | от 32768 до 32767 (при 2 байтах) или от 2 147 483 648 до 2 147 483 647 (при 4 байтах) | signed int |
unsigned int | 2 или 4 байта | от 0 до 65535 (для 2 байт) или от 0 до 4 294 967 295 (для 4 байт) | unsigned |
long | 4 или 8 байт | от -2 147 483 648 до 2 147 483 647 (4 байта), либо -9223372036854775807 до +9 223 372 036 854 775 807 (8 байт) | long int, signed long int, signed long |
unsigned long | 4 или 8 байт | от 0 до 4 294 967 295 (4 байта) или от 0 до 18 446 744 073 709 551 615 (8 байт) | unsigned long int |
long long | 8 байт | от -9223372036854775807 до +9223372036854775807 | long long int, signed long long int, signed long long |
unsigned long long | 8 байт | от 0 до 18446744073709551615 | unsigned long, long int |
float | 4 байта | от +/- 3.4E-38 до 3.4E+38 | |
double | 8 байт | от +/- 1.7E-308 до 1.7E+308. | |
long double | 10 байт (80 бит), 96 бит или 128 бит | от +/- 3.4E-4932 до 1.1E+4932 | |
void | тип без значения |
Примеры объявления переменных:
int main()
{
int a;
unsigned int a;
float f;
int su, prime = 7; five = 5;
char c, c2 = 'A', m=10;
}
Если не задано начальное значение переменной, то в ней хранится "мусор", оставшийся от предыдущего использования ячеек памяти.
Суффиксы
В языке Си любое десятичное число по умолчанию считается либо int/long либо int/long long int. Когда происходит присваивание числа переменной, тип которой отличается от этих типов происходит преобразование числа в тип указанный у переменной. Что бы избежать этого преобразования можно явно указать к какому типу принадлежит число. Для этого используются суффиксы.
Тип | Суффикс |
---|---|
unsigned int, unsigned long int и unsigned long long int | u или U |
unsigned long int и unsigned long long int | ul или UL |
long long int | ll или LL |
unsigned long long int | ull или ULL |
Пример объявления переменной с суффиксом:
unsigned number = 123456789u;
Спецификаторы классов памяти и квалификатор const
- const Значение не будет меняться после инициализации. Пример: const unsigned int a = 123; При попытке изменить переменную произойдет ошибка компиляции.
- static Место под переменную будет выделено в статической памяти, поэтому доступ к ней возможен во время всего времени работы программы. Инициализация выполняется до начала выполнения программы.
- extern Глобальная переменная объявляется и инициализируется в другом файле. Доступ к переменной возможен во время всего выполнения программы.
Оператор присваивания и побочный эффект
Операции присваивания в сложных выражениях могут вызывать побочные эффекты, так как они изменяют значение переменной. Побочный эффект может возникать и при вызове функции, если он содержит прямое или косвенное присваивание (через указатель). Пример побочного эфекта при вызове функции:
prog (a,a=k*2);
Примеры побочных эффектов в выражениях:
int main(void)
{
int a, b, x=5, y, z;
a = 5; //положить целое число 5 в переменную a
x = x + 20; // x=25 побочный эффект
y = (x - 15) * (x + a); // y=300
z = y = a+1; // y=6 z=6 побочный эффект
}
Арифметические операции над целочисленными значениями
- сложение "+"
- вычитание "–"
- умножение "*"
- деление нацело "/"
- остаток от деления нацело "%"
При делении нацело результат всегда округляется в сторону нуля и выполняется равенство (a/b)*b + a%b = a
, поэтому знак остатка совпадает со знаком делимого.
Явное приведение типов
Для явного приведения типов имя типа указывается в круглых скобках перед переменной или выражением:
int X;
int Y = 200;
char C = 255;
X = (unsigned char)C * 10 + Y;
Чтобы избежать неоднозначностей, рекомендуется явно указывать знаковость для типа char -1 или 255 иначе переменная С приводится к типу int.
Неявное приведение типов
При вычислении арифметических операций с двумя операндами, а также при выполнении операции присваивания может автоматически выполняться неявное преобразование операндов.
- Если один из типов операндов – вещественный, то второй операнд тоже приводится к вещественному типу.
- Если есть операнд целого типа короче, чем int и все значения этого типа могут быть представлены как int, то он преобразуется к int; иначе - к unsigned int.
- Для операндов целых типов неявное приведение типов управляется целочисленным рангом приведения типа.
Примеры правила 1:
float f;
f = 3/2; //целочисленное деление f=1.0
f = 3./2; //вещественное деление f=1.5
int a = 7;
float x;
x = a / 4; // 1
x = 4 / a; // 0
x = (float)a / 4; // 1.75
x = 1.*a / 4; // 1.75
Примеры правила 2:
short i, x=5,y=-2;
i = x + y;
переменные x и y сначала расширяются до типа int, выполняется сложение, а затем результат помещается в i
Примеры правила 3:
unsigned int u = 50;
int i = -500;
int answer = i / u; // answer = 85899335.
i будет приведен к беззнаковому типу и его значение будет равно 232-500 вместо -500, а результат деления будет приведен обратно к знаковому типу int
Унарные операции
Унарные операции также являются операциями с побочным эффектом.
- Инкремент “++” - увеличение операнда на единицу
- Декремент “--” - уменьшение операнда на единицу
Есть две формы унарных операций - постфиксная и префиксная. В первом случае сначала происходит присваивание значения а потом унарная операция, во втором случае сначала инкремент или декремент, а потом присваивание:
Постфиксная форма:
int a, b=7;
a = b++; // a=7 b=8
Префиксная форма:
int a, b=7;
a = ++b; // a=8 b=8
Точка следования
Точкой следования (sequence point), называется место в программе, в котором все побочные эффекты предыдущих вычислений закончены, а новые – не начаты. Точками следования в программе являются:
- конец полного выражения
- при выполнении операции x , y – между вычислением x и y;
- при выполнении операции z ? x : y – между вычислением z и вычислением x либо y; (рассмотрим это позднее)
- при вызове функции – перед выполнением ее тела и после вычисления ее аргументов;
- при выполнении операций x && y и x || y – между вычислением x и вычислением y.
Пример точки следования:
int a, b, c;
a = (a + b) * (c + 3); // после вычисления всего выражения.
int a, b = 10, c;
a = b++ + ++b; // ТАК НЕЛЬЗЯ !!! Дважды модифицируется одна переменная !!!}
a = (c = 3) + (c = 3); // ТАК НЕЛЬЗЯ !!! Дважды модифицируется одна переменная !!!
Самостоятельная работа
Вопросы для самопроверки
Какие имена переменных верные?
- ABCdf
- h&m
- 4you
- Иван
- “GeekBrains”
- super173
- [goodname]
- _my_string
- a*b
Задачи
Целой переменной k присвоить значение, равное сумме цифр в записи целого положительного трехзначного числа x.
Решение
int main(void)
{
int n=123;
int sum;
sum = n%10; //sum = 3
sum += (n/10)%10; //sum = 5
sum += (n/100)%10; //sum = 6
}