Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

README.md

2025-01-03-05

Мнимый полиморфизм в C

Видео на Youtube: https://youtu.be/-NO8gfHzg4Q

Много умных слов в комплекте к полиморфизму

  • Каламбур типов
  • Типобезопасность
  • Параметрический — Перегрузка — Приведение типов — …

Зачем?

Что у нас есть из инструментов?

  • Неявное приведение типов
  • strtol() и strtod() из <stdlib.h> (ну и itoa() туда же)
  • Указатель void может указывать на что угодно
  • Макрос _Generic (стандарт C11)
  • Тип данных «структура» (struct)
struct dollar {
	int d;
	char * ru;
	char * en;
};

struct dollar D = {.d = 100 }
struct dollar R = {.ru = "сто"}

// ? D==R 
  • Тип данных «объединение» (union)
struct dollar {
	char * type;
	union {
		int d;
		char * ru;
		char * en;
	};
};

struct dollar D = {type = "integer", .d = 100 }
struct dollar R = {type = "по-русски", .ru = "сто"}
  • (может пригодиться) Не-число NaN из модуля <math.h> (компиляция!)
  • printf-подобные функции и __attribute__
  • Опция transparent_union в __attribute__ (не стандарт, только gcc)
  • Макросы работают только с литералами — то есть с текстом программы
  • Расширение структурных типов через анонимные внутренние структуры

Кодим

Приведение типов случается и без нашего желания

  • int == char
  • int x = 7; double y = x + 0.0;
  • NULL автоматом приводится к типизированному указателю
  • int вообще пожирает всё, что можно

«Печатать попроще»

  • printf(”%d\n”, i); — это как-то перебор
  • Пример: приучаем к программированию на C людей, покусанных JavaScript’ом
  • Пока жить без переменных
  • Пока спрятать шаблоны вывода
  • Начать с печати зашитых в код чисел и слов
  • Терпеть отсутствие точки с запятой
  • Выводить и данные, и их тип
#define type(x) _Generic((x), \
	int: "int", \
	char *: "char *" \
	)
	
#define print(x) _Generic((x), \
	int: p_int,
	char *: p_str,
	)(x);

А если аргументов два?

  • Пример: квадратное уравнение по двум корням
  • Выводим подробно всякие разные данные
  • _Generic — макрос и работает с литералами; это трудно держать в голове
  • Макросы позволяют конструировать имя конечной функции
  • _Generic позволяет разветвлять макрос на типизированные функции
  • Если зависимость от типа можно конвертнуть в единый код (скажем, строку), то и _Generic можно использовать прямо в тексте программы
  • Управляющее выражение в _Generic не вычисляется!
# _Generic((x)) раскидывает на макросы + вызов
# _Generic((y)) после этогона имена функций

Продолжение с произвольными наборами аргументов произвольного типа — следует