# 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 вообще не будет проблем, там просто присвоятся все биты
---