---
# System prepended metadata

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

---

# 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

Синтаксически - тоже самое, что и структура

**Разница только в одном** - в том, как он **хранится в памяти**.

![](https://i.imgur.com/I9MWHA4.png)
![](https://i.imgur.com/MSEpdjQ.png)

Это структура в которой всё элементы побайтово лежат поверх друг друга. Размер 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;
}
```

Тоже самое, что и глобальная переменная.

Из минусов осталось:
* Ломает многопоточность