# 05 Лекция Полная версия [TOC] ## Целочисленные простые типы - В стандарте `int` определен как не хуже чем - `(-32767 ... 32767)` (`2^16-1`), именно в десятичной системе счисления, такой диапазон, не важно сколько битов в одном байте\ В реальности `int` соответвует диапазону - `-2^32 ... 2^32-1` - Модификатор (типа) `short int` по стандарту не шире `int` (32 бита)\ по факту - 16 бит - Модификатор (типа) `long int` по стандарту не меньше `int` (32/64 бита)\ по факту - 32/64 бита (Козлы тут Microsoft, под win при компиляции под 32-64битную программу `long int` соответсвует 32 битам, в Linux - при компиляции под 32 - 32, под 64 - 64) - Модификатор (типа) `long long int` по стандарту не меньше `long int` (64 бита)\ по факту - 64 бита > "long long long" is too long for gcc --- - Модификатор (типa) `unsigned int`, беззнаковое `int`, может применятся с любыми другими\ (по факту (для `int`) - `0 ... 2^32 - 1`) > `int` можно опустить в любых модификаторах для `int` --- **Создать новый тип** (создание синонимов типов) ```c typedef unsigned int uint; //задать тип с названием uint, и смыслом unsigned int uint a, b; //можно использовать как полный синоним unsigned int ``` > отличается от `define` тем, что это не простая текстовая замена, а создание нового типа, например: ```c= #define X int // X заменяет на int unsigned X a; //скомпилируется //-------------------------------------// typedef int y; //unsigned y b; //не скомпилируется ``` > К `typedef` новому типу (синониму) нельзя применить никакие модификаторы (`unsigned`, `long` и др.) --- - `char`, целочисленный тип, может быть знаковым или нет (`-128..127 / 0..255`, 1 байт или 8 бит)\ `unsigned char` -> `0..255`\ `signed char` -> `-128..127` (ключивое слово `signed` в си имеет смысл только тут) * Значения от 0 до 127 полностью кодируют ASCII, вторую часть бита занимает текущая кодовая страница системы. * `signed` можно применять к любым целочисленным переменным (но все кроме `char` по умолчанию - `signed`) --- - `_Bool` занимает **1 БАЙТ** (минимально адресуемая ячейка памяти), можно написать `bool` подключив заголовочный файл `#include <stdbool.h>` (также получите `true` и `false`) * В си изначально не было bool, true и false - из-за ненадобности > В стандарте Си нет ничего про `true` и `false`, только про (`1` и `0`) ## Операции сдвига Применяется только по целочисленным переменным > Модулярная арифметика (целочисленная) по стандарту определенна только в беззнаковых числах Сдвиг налево `<<` все битики сдвинуть на один влево, старший (самый левый) стереть, младший (самый правый) в 0, - **эквивалентен умножению на 2** * В беззнаковых числах гарантируется модулярная арифметика * В знаковых числах ничего не гарантируется модулярная арифметика Сдвиг направо `>>` все битики сдвинуть на один вправо, младший (самый правый) стереть, сдвигов `>>` (направо) есть 2: 1) Логический сдвиг направо - эквивалентный беззнаковому делению на 2 с округ вниз (беззнаковые числа) - **старший бит (самый правый) делает 0** 2) Арифмитический сдвиг направо - эквивалентный знаковому делению на 2 с округ вниз (знаковые числа) (проблема в том, что первый бит так или иначе используют для знака и непонятно куда его девать, сдвигать или нет) - **старший бит (самый правый) делает оставляет** Так происходит из-за представления чисел в компьютере ```c 5 >> 1; // == 2 //101 >> 1 = 10 == 2 -5 >> 1; // == -3 //11111011 >> 1 = 10111101 == -3 (Арифметический сдвиг) ``` --- > То есть если мы напишем `int a = -140; a /= 8;` - компилятор не имеет права съоптимизировать это до `a >>= 3;`, тк округление у `>>` идет вниз! В стандарте операция побитового сдвига направо для отрицательных чисел не определенна! (в 23 стандарте скорее всего поправять, тк признают числа - в качестве формы `дополнение до 2х`), то есть компилятор может посмотреть что здесь есть [Undefined Behavior](https://ru.wikipedia.org/wiki/%D0%9D%D0%B5%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D1%91%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D0%BE%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5) и просто выкинуть эту строчку. ## Грабли Знаковые переполнение в стандарте тоже неопределенно: ```c for(int i = 5; i > 3; i++) { ///code... } ``` > Скомпилировав это под `gcc` с оптимизациями можно легко получить бесконечный цикл! --- Беззнаковое переполнение в стандарте четко определенно: ```c unsigned int a = -1; //эквивалент = (-1)%(2^32), по математическому модулю ``` > в дополнение до 2x вообще не будет проблем, там просто присвоятся все биты ---