---
# System prepended metadata

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

---

# 02 лекция Полная версия


```с
#include <stdio.h>

int sum(int a, int b)
{
    return a + b;
}

int main(void)    
{
    int a=3, b=5; 
    printf("a+b=%d\n", sum(a, b));
    return 0;    
}
```

Так не скомпилируется (ниже)
```с
#include <stdio.h>

int main(void)    
{
    int a=3, b=5; 
    printf("a+b=%d\n", sum(a, b));
    return 0;    
}

int sum(int a, int b)
{
    return a + b;
}
```

:::warning
-Что нужно сделать, чтобы оно работало?
:::spoiler Ответ
-Нужно сообщить компилятору, что она существует, по факту написать прототип функции (обьявить функцию)
:::

```с
#include <stdio.h>

int sum(int, int);

int main(void)    
{
    int a=3, b=5; 
    printf("a+b=%d\n", sum(a, b));
    return 0;    
}

int sum(int a, int b)
{
    return a + b;
}
```
В этом случае можно расположить реализацию функции после вызова.
Но тогда нам нужно прописывать прототипы всех стандартных функций, это слишком долго и муторно, по этоиу мы подлючаем стандартные заголовочные файлы, в который и прописаны это прототипы. например для ввода вывода: `#include <stdio.h>`

:::info 
-обязательно ли писать имена аргументов в обьявлении?
:::spoiler Ответ
-нет.\
(Не знаю, про что это - пока обязательно, в 23 возможно поправят)
:::

---
**Как можно написать реализацию функции в другом файле?**
:::warning
> [color=#B22222] sum.c
```с
int sum(int a, int b)    // можно релизовать в этом файле
{
    return a + b;
}
```

> [color=#32CD32] main.c 
```с
#include <stdio.h>

int sum(int a, int b);     // если обьявить

int main(void)    
{
    int a=3, b=5; 
    printf("a+b=%d\n", sum(a, b));    // можно использовать
    return 0;    
}
```
:::
**Когда есть прототип, функция может быть реализованная не только после, но и в другом файле**


ИЛИ
:::success 
> [color=#B22222] sum.c
```
int sum(int a, int b)    // можно релизовать в этом файле
{
    return a + b;
}
```
> [color=#4682B4] sum.h
```
int sum(int a, int b);    // можно обьявить в этом файле
```
> [color=#32CD32] main.c 
```
#include <stdio.h>
#include "sum.h"         // можно подключить заголовочный файл
                         // "" пишится вместо <> тогда, когда у вас подключаемый файл находится в текущей рабочей папке 
int main(void)    
{
    int a=3, b=5; 
    printf("a+b=%d\n", sum(a, b));    // можно использовать
    return 0;    
}
```
:::success
При компиляции `#include <>` подключаемый файл сначала ищется в стандартных каталогах, а потом в текущей рабочей папке
При компиляции `#include ""` подключаемый файл ищется только в текущем рабочем каталоге
*текущая рабочая папка, в данном случае, откуда запустили компилятор
:::
>текущая рабочая папка в остальных случаях (в других контекстах, например при открытие файла) - место откуда запустили ваш `.exe` (исполяемый файл, `.exe` - это расширение исполняемых файлов под `windows`)
---

## Компиляция 
Как всё это работает? Обычно, как во многих языках, процесс компиляции состоит из *двух* этапов:
1. Компиляция - во время процесса получаются обьектные файлы расширения `.o` или `.obj` обычно, компилируются только файлы `.c`  и независимо друг от друга.
2. Линковка - получается `.exe` (если win), он собирает всю программу вместе, и вставляет нужные куски из других файлов на место недопереведенных.

> Компиляция начинается с предпроцессора

`.obj` - полуфабрикат, где часть кода переведенна в машинный код, а кое что ещё недопереведенно, например недопереведенно будет вызов функции `sum` в `main` в последнем примере выше.

Если мы обьявим функцию но не реализуем её нигде? Программа скомпилируется, но не слинкуется. (или окажется несколько функций с одинаковым именем в нескольких файлах, должны совпасть имена функций и типы принимаемые аргументы) (или если нет `main`)

На самом деле выполнение работы начинается не с `main`, а с `runtime`, служебных си'шных функций, которые инициализуют окружение (например парсят аргументы `main`, иниц глобальные аргументы), а он уже вызывает `main`. 

> Старт программы - недра системы->runtime C->main 
> Точка входа - main

Линковка может работать с разными языками, ей вообще не важен язык.

:::danger
-Во время линковки мы компилируем файлы из одной директории (которые лежат в одной папке)?
**-Нет, во время линковки мы компилируем и собираем вместе то, что мы дали линковщику**
:::

#### Про DLL
`.dll` - это тоже самое, что и `.exe`, но без точки входа (что-то экспортировать), призваны для уменьшения времени компиляции, и для сокрытия исходного кода.

#### Про документацию:
:::info
Рекомендация - читать документацию на английском
Программисты пишут документацию на английском, на других языках её очень лень писать, и очень часто перевод документации - машинный, или каким нибудь гуманитарием. По этому смысл в такой документации очень искажен. 
(тоже самое про [ru.wikipedia.org](https://ru.wikipedia.org/))
:::

#### Про поисковики:
:::info
Девиз Яндекса - найдется всё (зарос рекламой и ведёт себя неприлично)
Девиз Google - найдётся то, что ты искал
:::

---

### LTCG
***Link Time Code Generation***
Смысл - оптимизировать всю программу. Компилятор видит каждый файл программы **НЕзависимо**, поэтому что-то съоптимизировать между файлами просто принципиально не может. Если мы хотим дать возможность съоптимизировать программу целиком - применяется специальный хитрый вариант компиляции, когда `.obj` дает не машинный код, а промежуточный код этого компилятора, а потом линкер на этапе линковки снова вызывает компилятор, уже для всего общего промежуточного кода, и он его докомпилирует до машинного. Для этого линкер и компилятор должны 'дружить'.

**Name Mangling**\
Проблема в том, что на самом деле имя у этих функций не одинаковое, и когда всё это компилируется в `.obj` линкер без понятия плюсы там или нет и т.д. Если вы линкеру дадите несколько функций с одинаковым именем - он вас отругает. По этому ++ этим функциям дают неодинаковые имена, они к имени функции добавляют всякие @? и т.д. где этими магическими символами кодируют типы аргументов этих функции, то есть на самом деле имена этих функций уникальные, просто с добавкой. 
По этому если мы создадим один файл .c, а другой .cpp то у нас не скомпилируется, тк у одной и той же функции будет раные имена (в си++ туда добавятся магические символы) и линковщиу не сможет найти реализацию вызываемой функции.
**Это лечится**, если сказать компилятору C++ не трогать имя, я хочу настоящее имя функции - `extern "C" void f (int x);`, но тогда перегрузить функцию `f` не получится.
В стандарте **Name Mangling** не описан, и предугадать его не получится никак, тк даже один компилятор в разных версиях использует разные генерации этих имен 
(совместимость на двоичном уровне у ++ гораздо хуже чем у Си)

> Мы не хотим компилировать разные части разными компиляторами

#### Ещё одно значение си
Си выбран стыкующим языком, если мы хотим пристыковать к одному языку код на другом языке - то эта штука практически всегда происходит через си'шный интерфейс (либо быть си, либо через стыковку по правилам си) 

---