# 03 лекция Полная версия ## За жизнь Rust - язык без стандарта, свой компилятор языка без стандарта создать невозможно, тк то, как работает компилятор разработчика языка и является фактически стандартом. [IEEE 754-2008](https://ru.wikipedia.org/wiki/IEEE_754-2008) - как представляются числа в современном компьютере (C/C++) Вольный пересказ - https://www.softelectro.ru/ieee754.html ## Переменные и Операторы `int a, b = 5; // переменная a не инициализируется` > Инициализуется только те переменные у которых стоит `=` Локальные переменные без инициализации содержат мусор (рандомное значение), тк под локальные переменные место на стеке выделяется, но ничем не заполняется, может случиться 0, может не 0, из разных запусков - может случиться разное, из разных компиляций (release/debug) может случиться разное. Вообще, ошибки обращения к неиницилизированным переменным - это очень частые ошибки. Как искать обращение к неинициализированным переменным 1) Статические ситемы (анализаторы кода в онлайне, привязан к среде разроботки, замедляет её) 2) Динамические ситемы (может быть не привязан к среде, проверка при запуске под ним, бешенное замедление работы программы при запуске под ним, для больших программ можно не дождаться) например [Intel Inspector](https://www.intel.com/content/www/us/en/developer/tools/oneapi/inspector.html) --- ```c int main(void) { int a, b = 0, c; // b - инициализируется // Выделилось место на стеке для a, b и c return 0; } ``` > `//` и `///` - это комментарий, начиная от этого места до конца строки (до перевода строки), компилятор игнорирует, можно писать что угодно > если пишите комментарии на русском, надо посмотреть, чтобы кодировка файла в средее (текстовом редакторе) была `UTF-8` ```c a = b + 3; //a == b + 3 a += b; // полный синоним a = a + b; //результат a == b + 3 + b // (как и многие другие бинарные операции просто короткая запись) // выдает результат в си значение a, после операции ``` --- -многие вещи в C/C++ имеют результат, некое значение, например операция `=` (присваивания) тоже имеет результат, почему можно писать `a = b = c`? (что это значит?) ```c a = b = c; // эквивалент a = (b = c) или b = c; a = c; ``` > то есть операция `=` вместо того, чтобы просто присваивать ещё и отдает значение которое она присвоила. `a = b;`, `a`, слево от `=` - то куда присваиваем, `b`, справо от `=` - значение, которое мы присваиваем, операция присваивания всегда левостороняя. `a = b = c`, тоже самое `a = (b = c);` - всегда читается справа налево! ``` (a = b) = c; // в си НЕ СКОМПИЛИРУЕТСЯ // НЕльзя в значение записать значение, например 5 = 3; ``` > В значение нельзя записать значение, можно только в обьект (переменную) > Разница между объектом и значением видна только еcли мы туда пишем, если нет - нет В си++ - в результате операции присваивания `=` отдается обьект, то есть `(a = b) = c;` будет эквивалентом `a = b; a = c;`, но `a = b = c` всё равно юудет читаться как в си, справа налево! > Кажется, что это довольно глупая операция, ведь значение `b` сразу затрётся, но это если `a` и `b` простые типы, а в C++ всё может быть гораздо хитрее. Можно переобозначить операцию `=`, и он может выполнять совсем нетривиальные вещи. --- Надо поподробнее остановиться на `a++` (постфиксный инкремент) и `++a` (префиксный инкремент) ```c a++; // - постфиксная запись a = a + 1; ++a; // - префиксная запись a = a + 1; ``` > С точки зрения `a` разницы никакой (в си), а вот отдают они разное значение. `a++;` результат - значение `a` до увеличения\ `++a;` результат - значение `a` после увеличения ```c a = 2; b = a++; // a=3, b=2 // сначала отдает значение, затем увеличивает ``` ```c a = 2; b = ++a; // a=3, b=3 // сначала увеличивает, затем отдает значение ``` > Класс - обьединение переменных и функций, как структуры в си, только ещё со своими функциями, методами. > В C++ если обьекты обычные (простые типы) - разници нет никакой, если это какие-то классы, то для них могут быть переопредленны операторы `a++` или `++a`, и они могут означать разное. В плюсах `a` может оказаться классом, а если так - `a++` будет создавать временный обьект, копию класса, что может сильно замедлять программу, например цикл. В двух словах: для сложных объектов в C++ вполне возможно, что будет оверхед (`i++` может создать временный объект), для простых int'ов – нет, для отдельно стоящего `i++` точно такой же код, как и `++i`. **+, =, ++ и прочие операторы в C++ можно перопределить!** (нельзя переопределить `.` и `:`) ### На что обратить внимание? Один и тот же символ может означать разные операции, в зависимости от контекста, например `-`, может быть вычитанием, когда он используется в бинарном контексте, и может быть инвертированием знака, когда используется в унарном контексте. ```c c = a - b; //вычитание, бинарный контекст a = -a; //инвертирование знака, унарный контекст ``` У `*` вообще три разных контекста, бинарный, унарный и при создании переменной. ```c c = a * b; //умножение, бинарный контекст с = *ptr; //разыменовка, унарный контекст int *d; //создание указателя, контекст при создании переменной ``` Хитрых операций много, а вот символов нет, в те времена (написания си) даже большие/маленькие буквы не везде различали **У операций есть приоритет!** При одинаковом приоритете операции выполняются в нужном порядке, например для `+-` это слева направо, для `=` справа налево. То есть порядок зависит ещё и от контекста. (правила - [Operator Precedence](https://en.cppreference.com/w/cpp/language/operator_precedence) >`a+++++a` что это означает в си? > >`(a++)+(++a)`, НЕ `((a++)++) + a` потому что в си операция `++` отдает значение, а не обьект! В C++ `i++` и `++i` могут вернут объект Не надо писать так`c = (a++)+(++a);` Нельзя в одной строке менять 2 раза переменную, выдаст неопределенное значение (зависит от порядка в моменте), тк порядок выполнения в си неопределён! **Никогда не меняйте в выражение дважды одну переменную!** Для большинства бинарных операций порядок выполнения не определен Это справедливо и вызова функции нескольких аргументов: для аргументов функции, никто не обещает в каком порядке посчитаются аргументы функции, гарантируют, что они посчитаются перед непосредственном вызовом функции `c = f() + g();` никто не обещает какая функция будет выполнена первой! ```c int sum(int a, int b) { return a + b; } int print(int a) { printf("%d\n", a); return a; } int main(void) { int result = sum(print(4), print(3)); //result == 7 // неопределенно в какой порядке напечатается на экран // неопределенно вызовется сначала print(4) или print(3) // гарантируется выполнение print(4) и print(3) до непосредственного вызова sum() int result_2 = print(4) + print(3); // в такой записи порядок тоже неопределён // гарантируется выполнение print(4) и print(3) до сложения } ```