# 10 Лекция Полная версия
[TOC]
## Структуры
### Как отключить выравнивание
Зачем - например, для работы с файлами можно описать структуру чтобы её внутреннее устройство соответствовало один в один расположению данных в файлике. Читать так файли можно не поэлементно а одной операйией чтения. (Расположение данных должно точно совпадать) (Быстрее обычного способа)
В таких случаях вырвнивание можно отключить с помощью флагов компиляции (компиляторозависимо) (код может начать работать существенно медленее)
Для VS (Microsoft)
```c
#programa pack (push, 1) //без выравнивания
// (Пушим старое выравнивание на стек)
//code - описываем структуры
// которое хотим чтобы плотно упаковывались
#programa pack (pop) //выравнивание структур на дефолтное
```
Для Clang/GCC
```c
struct A __attribute__ ((packed))
{
//code
};
```
## Про размер в си
Размер какого-то обьекта - типа, переменной, массива в C/C++ можно узнать с помощью **оператора** `sizeof`, например: (в байтах)
```c
int a;
sizeof a == 4;
sizeof(unsigned int) == 4;
int arr[10];
sizeof(arr) == 40;
```
Скобки можно иногда не писать, это не функция!
Полученное число - это размер **типа выражения** в скобках в **байтах**!
---
К слову:
```c
struct A
{
int x;
double y;
char z[4];
} a[10];
struct B
{
double y;
int x;
char z[4];
} b[10];
struct C
{
int x[10];
double y[10];
char z[40];
} c;
sizeof(a) == 240; //байт
sizeof(b) == 160; //байт
sizeof(c) == 160; //байт
```
---
Тип выражения - `typeof`, есть в некоторых компиляторах, предлагают добавить в стандарт C23. По сути `typeof` уже существует, тк до того как посчитать размер в памяти нужно почитать тип выражения.
---
## Union
Синтаксически - тоже самое, что и структура
**Разница только в одном** - в том, как он **хранится в памяти**.


Это структура в которой всё элементы побайтово лежат поверх друг друга. Размер union - sizeof максимального элемента. Может использоваться для создания переменных с разными типами. (обычно вместе со структорой, которая хранит активный тип) (ещё можно прочитать битики floata, напрмер))
Все элементы начинаются с адреса 0, массив считается одним элементом, структура тоже будет считаться одним элементом, со всеми своими дырками
Нужны не очень часто, но там где их нет, но они нужны - уровень извращений зашкаливает, и он будет гораздо выше чем здесь.
## Указатели
В интернете есть много картинок про сравнение перехода с C на Python (например, и наоборот). Во многом легкость изучения других языков после C/С++ обуславливается тем, что здесь приходится вручную управлять памятью (=> существуют указатели).
Когда говорят что на Java можно писать эффективный код - имею ввиду, что для этого программист должен обладать высшей калификацией, так как чтобы писать эффектывный код нужно понимать что язык прячет от вас и как он это длает, C, меньше С++ прячут значительно меньше чем Java => присать быстрый код на них проще (несмотря на то, что писать просто код на них сложнее)
В последнее время почему-то чем быстрее удаётся накодить программу - тем лучше (лучше выпустить на неделю раньше, чем исправить пару багов), такой подход как раз и провоцирует использование простых, однако неэффективных языков, например Python, Java
**Указатели** - идейно они довольно похожи на ярлыки в windows, если создать кучу ярлыков и один удалить, данные никак не поменяются. Ярлыки не содержат данные, только информацию как эти данные найти. На си тоже самое, только указатели строго типизированны, в указателе зашито то, на что он указывает. Указатель на `int` может указывать только на `int`. **Сами обьекты не содержат информации о типе обьекта**, `int` - это просто 4 байта в памяти. Информация о типе есть только в момент компиляции. По этому в C/C++ в момент компиляции указатель знает информация о типе.
**Занимают в памяти столько, какая разрядность программы** (32 или 64 бита)
Система обычно позволяет запускать меньшей и равной битности программы (иногда строго равной)
```c
int x; // int
int *p, a; // указатель на инт, и обычный инт
```
Есть религиозный момент, где ставить `*` рядом с `int` или рядом с именем переменной. Тк при создании переменной указатель относиться только к этой пеменной, а не типу, то следует её ставить рядом с переменной.
`*` может относиться к типу, но это редкость (в основном при создании указателя на функцию)
От того, где в C/C++ стоят пробелы - ничего не меняется!
```c
p = &x; // взять адрес в памяти переменной x
//и присвоить указателю p
// (унарный контекст &)
```
Указатель - чтобы работать с данными, другой смысл `*`: (унарный контекс)
```c
int y = *p; // обращение сквозь указатель
//(разьименовка указателя), y == x
//чтение сквозь указатель
*p = 2; // x == 2
//запись сквозб указатель
int **q=&p; // указатель на указатель
**q = 3; // x == 3, *q на p, **q на x
```
Тип указателя позволяет их коректно разименовывать
В си ссылок нет! (`int &a;`) (есть в си++)
## Про память
Обычные переменные, аргументы функции и т.д. создаются **на стеке** (храняться на стеке)\
Выделение памяти - проиходит **на куче**.
* стек - +- 2 мегабайта на процесс
* куча - сколько есть операт пам
Если привысить стек - ***программа упадет***, возможно молча, тк для вывода ошибки тоже нужно место на стеке.
### Глобальные переменные
Опишем переменную вне функции:
```c
int g = 2;
int f(int a)
{
return a;
}
int main(void)
{
f(8);
return 0;
}
```
`g` будет глобальной переменной. Такие переменные глобальные:
* **Одни на всю программу всегда**
* **Видно из всех функций**
* **Время жизни - глобальное**
* **По умолчанию - видимость только в файле**
+ обьявить в другом файле (строго без иниц):
+ `int g;` - C
+ `extern int g;` - C++,
+ `::g` - обратиться в С++ (когда имя скрыто локальной переменной)
* Создается до запуска main
* Уничтожается после окончания main
* Создается в секции данных (на куче)
* Размер должен быть известен в момент компиляции
Минусы глобальных переменных:
* Ломают многопоточность
* рекурсию
* очень сложно отлаживать (могут измениться в неожиданном месте)
> Глобальные переменные лучше не использовать без **Острой** необходимости
> Константы **рекомендуется** размещать в глобальной области
`static` по глобальной переменной **ограничивает видимость** текущим файлом.
### Static локальные переменные
Выглядит как локальная:
* видимость - локальная
* время жизни - глобальное
```c
int f(void)
{
static int a = 5; // иниц будет выполненно один раз первый
a++; // будет выполненно Каждый раз
return a; // будет выполненно Каждый раз
}
int main(void)
{
//здесь a не видно
f(); // == 6
f(); // == 7
f(); // == 8
return 0;
}
```
Тоже самое, что и глобальная переменная.
Из минусов осталось:
* Ломает многопоточность