#cpp
Day 41.
Кроме хорошо знакомого вам
Подразумевалось, что
после чего вы могли писать
То есть с помощью
Ещё утверждения можно было отменять с помощью
И больше это неправда.
Фактически это примитивная логическая база знаний.
Выше я писал «был», потому что в C11 #assert и #unassert не стало. Потому что фактически почти никто не реализовал. Все писали примерно:
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 41.
Кроме хорошо знакомого вам
assert был и ещё никак не связанный с первым #assert. Подразумевалось, что
#assert будет помогать генерировать какие-то утверждения для препроцессора. Например
#assert cpu(x86)
#assert os(linux)
#assert this(notes)
после чего вы могли писать
#if #cpu(x86) // true
...
#if #os(linux) // true
...
#if #this(notes) // true
...
#if #os(win) // false
...
То есть с помощью
#assert препроцессор записывал в отдельную табличку верные утверждения, а потом умел сообщать, есть ли такой факт. Причём проверка проводилась для predicate(argument). Ещё утверждения можно было отменять с помощью
#unassert cpu(x86)
И больше это неправда.
Фактически это примитивная логическая база знаний.
Выше я писал «был», потому что в C11 #assert и #unassert не стало. Потому что фактически почти никто не реализовал. Все писали примерно:
#define CPU_X86 1
#if CPU_X86
#ifdef CPU_X86
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
❤9🔥1
#cpp
Day 42.
Представьте такую ситуацию: Вы мегаумный программист, разрабатывающий инфру в какой-нибудь компании. И Вы хорошо понимаете, какие ошибки совершают ваши коллеги чаще других. Вы бы хотели оградить коллег от частых ошибок. Например, запретить пользоваться какой-то функцией из стандартной библиотеки и сообщить в ошибке альтернативу.
Или может вы пишете какой-то тулинг для сбора статистики и хотите подменить стандартную функцию своей, которая будет сначала собирать какую-то информацию, а потом как обычно вызывать стандартное решение.
Для решения таких задач можно подменить стандартный хедер на свой.
Для начала его надо реализовать:
И начать компилировать вашу программу как-нибудь так:
(тут мы указываем путь к хедерам, так как наш
Или через cmake как-то так:
Теперь пользователь будет писать
и вместо системного хедера подключится ваш. Круто?
А видите ли вы какую-нибудь проблему в реализации my_headers/string.h?
Например, что внутри мы тоже подключаем
Какая-то рекурсия!
Для решения этой проблемы некоторые компиляторы реализовали нестандартное расширение
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 42.
Представьте такую ситуацию: Вы мегаумный программист, разрабатывающий инфру в какой-нибудь компании. И Вы хорошо понимаете, какие ошибки совершают ваши коллеги чаще других. Вы бы хотели оградить коллег от частых ошибок. Например, запретить пользоваться какой-то функцией из стандартной библиотеки и сообщить в ошибке альтернативу.
Или может вы пишете какой-то тулинг для сбора статистики и хотите подменить стандартную функцию своей, которая будет сначала собирать какую-то информацию, а потом как обычно вызывать стандартное решение.
Для решения таких задач можно подменить стандартный хедер на свой.
Для начала его надо реализовать:
// my_headers/string.h
#pragma once
#include <string.h> // подключаем системный хедер
#define strcpy(...) static_assert(false, "Use strncpy instead")
И начать компилировать вашу программу как-нибудь так:
clang++ -I my_headers ...
(тут мы указываем путь к хедерам, так как наш
my_headers расположен первым, то и проверяться он будет первым)Или через cmake как-то так:
target_include_directories(
my_target
BEFORE PRIVATE my_headers
)
Теперь пользователь будет писать
#include <string.h>
и вместо системного хедера подключится ваш. Круто?
А видите ли вы какую-нибудь проблему в реализации my_headers/string.h?
Например, что внутри мы тоже подключаем
<string.h>, который (согласно нашей сборке проекта) будет искаться в my_headers/string.h. Какая-то рекурсия!
Для решения этой проблемы некоторые компиляторы реализовали нестандартное расширение
#include_next. Достаточно в нашем хедере использовать именно его:
#include_next <string.h>
#include_next будет инклудить указанный файл, но поиск файла будет осуществляться после того каталога, в котором находится текущий файл. То есть в нашем примере мы сразу пропустим директорию my_headers и начнём искать где-то ещё. Если у вас нет других string.h до системных хедеров, мы получим нужный файл из стандартной библиотеки. @thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍20🔥5❤3🤯2🌚1
#cpp
Day 43.
Так как писать код на препроцессоре бывает неимоверно неприятно, есть тулы в помощь. Например, ppstep, который позволяет интерактивно (пошагово) разбираться в раскрытии ваших макросов и всего вокруг.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 43.
Так как писать код на препроцессоре бывает неимоверно неприятно, есть тулы в помощь. Например, ppstep, который позволяет интерактивно (пошагово) разбираться в раскрытии ваших макросов и всего вокруг.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
😁6🤩4👍3
#cpp
Day 44.
Сегодня ссылка, где Paul Mensodines скрупулёзно поясняет механизм раскрытия макросов: How macro expansion works.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 44.
Сегодня ссылка, где Paul Mensodines скрупулёзно поясняет механизм раскрытия макросов: How macro expansion works.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍9
#cpp
Day 45.
Мы уже обсуждали, как сделать
Sequence это просто набор элементов в скобках:
Тут 5 элементов. Но конечно мы не ограничиваемся числами:
Основные операции иногда реализуются просто:
В конце на самом деле надо ещё как-то убрать
Другие операции могут быть чуть сложнее, но концептуально там ничего такого. В любом случае самим реализовывать вам не нужно. Берите
Там ещё и итерироваться можно, но про это завтра.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 45.
Мы уже обсуждали, как сделать
LIST, но есть и более свойственная препроцессору структура данных: sequence.Sequence это просто набор элементов в скобках:
(1)(2)(3)(4)(5)
Тут 5 элементов. Но конечно мы не ограничиваемся числами:
(a)(b)(c)
(int)(double)(bool)
(1)(2)()((),w,())(awoo())(())
Основные операции иногда реализуются просто:
#define SEQ_PUSH_FRONT(x, seq) (x) seq
SEQ_PUSH_FRONT(z, (a)(b)(c)) // (z)(a)(b)(c)
#define FRONT(seq) FRONT_I seq
#define FRONT_I(x) x
FRONT((a)(b)(c))
// FRONT_I(a)(b)(c)
// a
В конце на самом деле надо ещё как-то убрать
(b)(c), но сейчас это не так важно. Другие операции могут быть чуть сложнее, но концептуально там ничего такого. В любом случае самим реализовывать вам не нужно. Берите
Boost Preprocessor и крутите
BOOST_PP_SEQ_SIZE((a)(b)(c)) // 3
BOOST_PP_SEQ_ELEM(1, (a)(b)(c)) // b
BOOST_PP_SEQ_PUSH_BACK(seq, x)
Там ещё и итерироваться можно, но про это завтра.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍5🤯2🤓1
#cpp
Day 46.
Шагаем на ступеньку номер 7.
Мы бы могли с вами реализовать итерацию по sequence, но иногда лучше вовремя остановиться и заиспользовать что-то готовое:
Получим
Как это реализовано?
Ну вот примерно как вчера откусываете по одному токену из начала и применяете к нему «функтор». Чего непонятно-то???
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 46.
Шагаем на ступеньку номер 7.
Мы бы могли с вами реализовать итерацию по sequence, но иногда лучше вовремя остановиться и заиспользовать что-то готовое:
#define PRINT(r, data, elem) elem
BOOST_PP_SEQ_FOR_EACH(
PRINT,
_,
(a)(b)(c)(d)
)
Получим
a b c d
Как это реализовано?
Ну вот примерно как вчера откусываете по одному токену из начала и применяете к нему «функтор». Чего непонятно-то???
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍8🗿3👎1
#cpp
Day 47.
Я уже упоминал Paul Mensodines, который написал огромное письмо про механизм раскрытия макросов.
И упоминал про Boost.Preprocessor.
Вот Paul когда-то написал chaos-pp — настоящая глыба в мире препроцессорных библиотек. Там вообще всё что хотите. Рекурсия, высокоуровневые алгоритмы (
Правда её не так часто используют. Просто потому что она очень сложная (== высокий порог входа), без документации, а большинство задач решаются чем-то попроще.
Но как артефакт кайфово.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 47.
Я уже упоминал Paul Mensodines, который написал огромное письмо про механизм раскрытия макросов.
И упоминал про Boost.Preprocessor.
Вот Paul когда-то написал chaos-pp — настоящая глыба в мире препроцессорных библиотек. Там вообще всё что хотите. Рекурсия, высокоуровневые алгоритмы (
MAP, FOLD, FILTER, ZIP и др.), лямбды и частичное применение макросов, разные контейнеры (sequence, tuple, list). Правда её не так часто используют. Просто потому что она очень сложная (== высокий порог входа), без документации, а большинство задач решаются чем-то попроще.
Но как артефакт кайфово.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍13❤2
#cpp
Day 48.
Если вам нужна сравнительно мощная, но более современная альтернатива chaos-pp, стоит взглянуть на Metalang99.
Это хорошая попытка сделать препроцессор похожим на функциональный язык программирования. Но что более важно, проект хорошо документирован. chaos-pp в этом плане проигрывает (и служит скорее исследовательским артефактом).
Так что Metalang99 — ваш второй выбор (после Boost.Preprocessor).
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 48.
Если вам нужна сравнительно мощная, но более современная альтернатива chaos-pp, стоит взглянуть на Metalang99.
Это хорошая попытка сделать препроцессор похожим на функциональный язык программирования. Но что более важно, проект хорошо документирован. chaos-pp в этом плане проигрывает (и служит скорее исследовательским артефактом).
Так что Metalang99 — ваш второй выбор (после Boost.Preprocessor).
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
❤5👍4
#cpp
Day 49.
Одна из моделей, которую можно реализовать на макросах (хотя мы выяснили, что можно любую видимо) — continuation machine. Фактически это штука, в которой вы можете построить пайплайн работы с данными (но такими словами про неё не говорят, слишком современно). На картинке ниже страшная реализация для простого кейса работы с регистрами (разбирать мы ёе не будем, я хочу просто подышать.....).
Кстати репозиторий это что-то вроде оптимизированного интерпретатора Brainfuck. Есть и другие альтернативы: bfi, CPP_COMPLETE.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 49.
Одна из моделей, которую можно реализовать на макросах (хотя мы выяснили, что можно любую видимо) — continuation machine. Фактически это штука, в которой вы можете построить пайплайн работы с данными (но такими словами про неё не говорят, слишком современно). На картинке ниже страшная реализация для простого кейса работы с регистрами (разбирать мы ёе не будем, я хочу просто подышать.....).
Кстати репозиторий это что-то вроде оптимизированного интерпретатора Brainfuck. Есть и другие альтернативы: bfi, CPP_COMPLETE.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
❤11🤯3👍1
#cpp
Day 50.
Макросы можно класть на и доставать из (со) стека:
Не уверен, что понимаю, зачем это нужно.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 50.
Макросы можно класть на и доставать из (со) стека:
#define PRAMGA(...) _Pragma(#__VA_ARGS__)
#define POP(m) PRAMGA(pop_macro(#m))
#define X 1 POP(X)
#pragma push_macro("X")
#define X 2 POP(X)
#pragma push_macro("X")
#define X 3 POP(X)
#pragma push_macro("X")
#define X 4 POP(X)
X // 4
X // 3
X // 2
X // 1
Не уверен, что понимаю, зачем это нужно.
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍3🤪2🔥1
#cpp
Day 51.
Есть ещё несколько интересных репозиториев, связанных с препроцессором:
• datatype99 (фактически синтаксический сахар для генерации типов, но с дополнительными плюшками вроде паттерн матчинга)
• interface99 (Golang/Rust inspired интерфейсы для C99)
• boline (integer arithmetics with base 16).
У последнего код с вайбом ASCII-art.
И есть ещё подгон от подписчика про расширение в clang, позволяющее делать макросы рекурсивными. Названо оно
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
Day 51.
Есть ещё несколько интересных репозиториев, связанных с препроцессором:
• datatype99 (фактически синтаксический сахар для генерации типов, но с дополнительными плюшками вроде паттерн матчинга)
• interface99 (Golang/Rust inspired интерфейсы для C99)
• boline (integer arithmetics with base 16).
У последнего код с вайбом ASCII-art.
И есть ещё подгон от подписчика про расширение в clang, позволяющее делать макросы рекурсивными. Названо оно
__THIS_MACRO__:
#define fold_left(op, head, ...)(__VA_OPT__(__THIS_MACRO__(op,__VA_ARGS__)op)head)
fold_left(+, 1, 2, 3, 4) // раскрывается в ((((4)+3)+2)+1)
@thisnotes. Patreon, Boosty.
Спасибо Artyom Garkavy и niki4smirn.
👍7👏1