# 07 лекция C/C++
(02.04.2022)
## Про переменные
`volatile` - информирует компилятор, что значение переменной может меняться извне. Это может произойти под управлением операционной системы, аппаратных средств или другого потока. Поскольку значение может измениться, компилятор каждый раз загружает его из памяти.
```c
int t = time();
//...
//int t = time(); //может преместить туда, и тогда
printf("Time: %i\n", time() - t); //выведет 0
```
```c
volatine int t = time(); //(оптимизатор, не трогай переменную)
//...
printf("Time: %i\n", time() - t); //выведет правильно
```
Волатильную целочисленную переменную можно объявить как:
`int volatile х; volatile int х;`
Чтобы объявить указатель на эту переменную, нужно сделать следующее:
`volatile int *х; int volatile *х;`
Волатильный указатель на неволатильные данные используется редко, но допустим: `int *volatile х;`
Если вы хотите объявить волатильный указатель на волатильную область памяти, необходимо сделать следующее:
`int volatile *volatile х;`
Волатильные переменные не оптимизированы, что может пригодиться. Представьте следующую функцию:
```c
int opt = 1;
void Fn(void) {
start:
if (opt == 1)
goto start;
else
break;
}
```
На первый взгляд кажется, программа зациклится. Компилятор может оптимизировать ее следующим образом:
```c
void Fn(void) {
start:
int opt = 1;
if (true)
goto start;
}
```
Вот теперь цикл точно станет бесконечным. Однако внешняя операция позволит записать 0 в переменную `opt` и прервать цикл.
Предотвратить такую оптимизацию можно с помощью ключевого слова `volatile`, например объявить, что некий внешний элемент системы изменяет переменную:
```c
volatile int opt = 1;
void Fn(void) {
start:
if (opt == 1)
goto start;
else
break;
}
```
Волатильные переменные используются как глобальные переменные в многопотоковых программах — любой поток может изменить общие переменные. Мы не хотим оптимизировать эти переменные.
## Про указатели
`int (*p)(int, int)`, `p` - это указатель на функцию возвращающую `int` и принимающую два аргумента типа `int`
Имя функции - указатель на эту функцию:
```
int f(int a, int b)
{
//...
}
int (*p)(int, int);
p = f;
int x = p(2, 4);
```
## Про выделение памяти
`int *p2 = realloc(p, new_size)` - изменяет размер выделенной памяти, на то, что попросили (и увел., и умен.) (может двигать или не двигать указатель, зависит от ситуации)
Может закончиться неудачей, если вернет NULL - не освободит память, правильный код
```
int *p = malloc(old_size);
{
int *p2 = realloc(p, new_size);
//если p исходно NULL - работает как malloc
if(p2) //p2 != NULL
p = p2;
else
//error
} // чтобы p2 уничтожился после этого
free (p);
```
`realloc(p, 0)` - НЕ освобождение памяти! (`malloc` и `realloc` тратит прамяти больше, чем вы просили!)
`realloc` - очевидно, медленно работает, не надо его писать в цикле, увеличивая рамер на `1`. (после иниц массива, можно изменить размер на строго нужное)
Если выделять память в 2 раза больше - если `realloc` не удался - можем попробовать выделить на четверть (главное, чтобы `1/4 != 0`).
## Про структуры
```
struct A
{
int x;
} *p;
(*p).x;
//или
p->x; // полный эквивалент
```
## За жизнь
`typedef` - это как создание переменной, но создание типа (как можно создать переменную, так можно создать и тип)
```
typedef int ( * structure_function ) ( struct A const * ,
struct A const * );
// создает тип указатель на функцию которая отдает int,
// принимает 2 константных указателя на структуру A,
// называется structure_function
```
Не трогали:
- Модель памяти и треды
# C закончился.
# C++
Синтаксический сахар - эквивалент для уменьшения кода. Плюс C++ в том, что идею можно отобразить меньшим кодом, минус - понять такой код сложнее
## Про преобразование типов
С - `void * <----> ...*`
С++ - `void * <---- ...*`
В C++ необходимо писать`int *p2 = (int *) realloc(p, new_size);`
## Перегрузка функций
Отключить - `extern "C"` перед обьявлением функции (нельзя давать комп С)
```
#ifdef __cplusplus
extern "C" {
#endif
//...code
#ifdef __cplusplus
}
#endif
```
Можно значения по умолчанию писать через
```
#ifdef __cplusplus
#define S(x) x
#else
#define S(x)
#endif
int f(int a S(=0));
```
не перегрузка: (аргументы по умолчанию)
```С++
int y(int a, int b = 0); //можно указывать сконца
y(2,4);
y(2); //y(2, 0)
```