Переменные.
Чтобы прочитать данные из памяти или записать даные в память необходимо знать адреса ячеек с которыми будут осуществляться действия. Так как различных данных у программ, включая промежуточные значения вычислений, огромное количество, то запомнить адреса ячеек практически не возможно. Поэтому для работы с данными используются переменные.
Переменная - это ячейка в памяти, которая имеет имя, адрес в памяти и значение. Значение может меняться в процессе выполнения программы путем записи нового значения вместо старого.
Имена переменных могут начинаться с латинской буквы или символа подчеркивания и могут содержать только латинские буквы, цифры или символ подчеркивания.
Типы данных.
Язык программирования Си является строго типизированным. А это значит, что при объявлении переменной необходимо объявить ее тип, под который будет выделено нужное количество памяти и который будет неизменным все время работы программы. Типы данных различаются диапазонами возможных значений и требуют для хранения разное количество байт. Это следует учитывать при разработке приложений, особенно при написании программ для контроллеров, которые обладают ограниченными размерами памяти. В таблице ниже перечислены все типы языка Си.
Название типа | Размер памяти | Диапазон значений | Псевдонимы |
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 signed< |
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); // ТАК НЕЛЬЗЯ !!! Дважды модифицируется одна переменная !!!
Комментарии ()