---
# System prepended metadata

title: 05 Лекция Полная версия

---

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

---