# 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** не описан, и предугадать его не получится никак, тк даже один компилятор в разных версиях использует разные генерации этих имен
(совместимость на двоичном уровне у ++ гораздо хуже чем у Си)
> Мы не хотим компилировать разные части разными компиляторами
#### Ещё одно значение си
Си выбран стыкующим языком, если мы хотим пристыковать к одному языку код на другом языке - то эта штука практически всегда происходит через си'шный интерфейс (либо быть си, либо через стыковку по правилам си)
---