C++ - самый, сука, константный язык
Глядите, у нас есть базовый пример:
^ Указатель на x
Можно менять указатель
Можно менять значение
^ Указатель на константное значение
Можно менять указатель
Нельзя менять значение
^ Константный указатель на значение
Нельзя менять указатель
Можно менять значение
Что ж.. а теперь барабанная дробь:
^ Константный указатель на константное значение
Нельзя менять указатель
Нельзя менять значение
Но тише, тише, это только начало:
^ Указатель на константный указатель на значение
Можно менять указатель
Нельзя менять значение указателя p
Можно менять само значение x (через
^ Константный указатель на константный указатель на константное значение
Нельзя менять указатель
Нельзя менять значение указателя p
Нельзя менять само значение x
Ладно, хватит! Я еще не стал душнить про
указатель на указатель на константный указатель на константный указатель на x
C++ штука такая. Живите с этим :)
Глядите, у нас есть базовый пример:
int x = 5;
int* px = &x;
^ Указатель на x
Можно менять указатель
Можно менять значение
const int* px = &x;
^ Указатель на константное значение
Можно менять указатель
Нельзя менять значение
int* const px = &x;
^ Константный указатель на значение
Нельзя менять указатель
Можно менять значение
Что ж.. а теперь барабанная дробь:
const int* const px = &x;
^ Константный указатель на константное значение
Нельзя менять указатель
Нельзя менять значение
Но тише, тише, это только начало:
int* const* ppx = &px;
^ Указатель на константный указатель на значение
Можно менять указатель
Нельзя менять значение указателя p
Можно менять само значение x (через
**ppx)const int* const* ppx = &px;
^ Константный указатель на константный указатель на константное значение
Нельзя менять указатель
Нельзя менять значение указателя p
Нельзя менять само значение x
Ладно, хватит! Я еще не стал душнить про
int* const* const** ppppx....указатель на указатель на константный указатель на константный указатель на x
C++ штука такая. Живите с этим :)
❤4👀1
this->CelebrateBirthday();
//TODO: :tada effect
И вот.. Подходит мой8-й год в С++ 17-й год жизни, и знаете? Я счастлив что встретил вас всех, с кем остались, а с кем, конечно, разошлись
И правда, еще 2 года назад, до начала Portal: Solver и всего этого я думал что к 16-17 годам буду как те самые подростки на вписках - алкоголь, курение и всякое подобное. Считал что моя жизнь увязнет в этом, но....
Сейчас проект, цель, будущее - и правда, это не произошло бы без всех вас.
Безусловно в общей картине влияние каждого - как капля в море, но именно существование этого, как кирпичик за кирпичиком, объединило всех нас здесь, в этом скромном, но теплом, окружении. И без вас - этот день не был бы таким приятным ;)
Спасибо
//TODO: :tada effect
И вот.. Подходит мой
И правда, еще 2 года назад, до начала Portal: Solver и всего этого я думал что к 16-17 годам буду как те самые подростки на вписках - алкоголь, курение и всякое подобное. Считал что моя жизнь увязнет в этом, но....
Сейчас проект, цель, будущее - и правда, это не произошло бы без всех вас.
Безусловно в общей картине влияние каждого - как капля в море, но именно существование этого, как кирпичик за кирпичиком, объединило всех нас здесь, в этом скромном, но теплом, окружении. И без вас - этот день не был бы таким приятным ;)
Спасибо
❤5🎉3
This media is not supported in your browser
VIEW IN TELEGRAM
⚡️ Portal: Solver запустили на Raspberry Pi 3B 2016...
Оптимизация не перестает удивлять
Что дальше?)
Оптимизация не перестает удивлять
Что дальше?)
😱4❤🔥2💯1
Экстравагантное использование препроцессора для избежания виртуализации
Когда я говорил про гибкость С++, я в буквальном смысле имел ввиду - С++ очень гибкий. И недавное, чисто обдумывая препроцессинг, мой мозг заметил одну интересную вещь....
Представим задачу с реверсивной зависимостью:
И потом где-то, где-то далеко, мы реализуем:
^ В целом неплохо, да? Но что меня, как Ардуинщика, смущает - виртуальные функции...
Во первых: само их существование - убивает меня, как человека, умеющего чувствовать железо
И второе (самое очевидное): - если другой разработчик банально забудет реализовать функцию из интерфейса?
И, относительно недавно заметил одну интересную вещь: Если мы сделаем файл с обьявлением функций, а затем просто будем подключат его и реализовывать все функции? Покажу на практике:
^ Мы просто объявили функции в безымянном, для компилятора, файле (Напомню - компилятор работает только с .cpp файлами)
А вот затем, в целевом файле, делаем такой фокус:
Иии, самое интересное, реализацию делаем напрямую в .cpp:
По сути, что мы сделали? При проходе препроцессингом, строка #include "RenderDeclaration.h" раскроется с содержимым внутри RenderDeclaration.h, то есть:
^ А затем уже линковщик подловит все обьявления функций с их реализациями в OpenGLRender.cpp и все будет хорошо
Но хорошо, вы скажите, это не гибко и вообще очень плохо. Но я вас спрошу: "Какая, черт побери, гибкость в фундаменте архитектуры, которая ну никак не меняется?!"
По сути, виртуализация - это очень тяжелая штука. Каждая виртуальная функция уже КАК МИНИМУМ занимает от 4 до 8 байт! (4 байта на 32 битной машине. 8 байт на 64 битной машине. Но не суть)
Например вы пишете движок, вы 1 раз реализовали класс для определенной графики - и забыли. Вам не нужно каждый раз менять что-то, особенно динамично - это не имеет смысла так такового (а оверхед будет иметь)
"А если человек хочет реализовать свой вариант графики?" - тогда он просто создаст новый класс, подключит файл с функциями, IDE ему сразу предложит/подскажет какие функции надо реализовать - реализуете и работаете. Все! А чтобы применить графику, достаточно (к примеру):
А затем, уже где-то под капотом движка:
И, если кто не понял, при проходе препроцессингом RENDER_CLASS заменится на ROpenGLRender и мы получим строку ROpenGLRender RenderClass;
И да, если я создам класс RVulkanRender, реализую функции, обновлю конфиг как #define RENDER_CLASS RVulkanRender, то получу тот же гибкий функционал при минимальных затратах. Никаких виртуальных функций, виртуальных таблиц и прочего
А в завершении могу добавить: При обновлении движка, создателю достаточно добавить новое обьявление в RenderDeclaration.h, а затем пользователь (работающий на движке) просто дополнит свой класс RVulkanRender новой функцией и все будет как раньше - без всякого "ой, я случайно забыл переопределить функцию"
What you don't use, you don't pay for. Think Cold.
Когда я говорил про гибкость С++, я в буквальном смысле имел ввиду - С++ очень гибкий. И недавное, чисто обдумывая препроцессинг, мой мозг заметил одну интересную вещь....
Представим задачу с реверсивной зависимостью:
// RenderInterface.h
class IRender
{
virtual void SetupScreen();
virtual void ClearScreen();
virtual void UpdateScreen();
};
И потом где-то, где-то далеко, мы реализуем:
// OpenGLRender.h
class ROpenGLRender : IRender
{
virtual void SetupScreen() override;
virtual void ClearScreen() override;
virtual void UpdateScreen() override;
};
^ В целом неплохо, да? Но что меня, как Ардуинщика, смущает - виртуальные функции...
Во первых: само их существование - убивает меня, как человека, умеющего чувствовать железо
И второе (самое очевидное): - если другой разработчик банально забудет реализовать функцию из интерфейса?
И, относительно недавно заметил одну интересную вещь: Если мы сделаем файл с обьявлением функций, а затем просто будем подключат его и реализовывать все функции? Покажу на практике:
// RenderDeclaration.h
void SetupScreen();
void ClearScreen();
void UpdateScreen();
^ Мы просто объявили функции в безымянном, для компилятора, файле (Напомню - компилятор работает только с .cpp файлами)
А вот затем, в целевом файле, делаем такой фокус:
// OpenGLRender.h
class ROpenGLRender
{
#include "RenderDeclaration.h"
};
Иии, самое интересное, реализацию делаем напрямую в .cpp:
// OpenGLRender.cpp
void ROpenGLRender::SetupScreen() { ... }
void ROpenGLRender::ClearScreen() { ... }
void ROpenGLRender::UpdateScreen() { ... }
По сути, что мы сделали? При проходе препроцессингом, строка #include "RenderDeclaration.h" раскроется с содержимым внутри RenderDeclaration.h, то есть:
// OpenGLRender.h
class ROpenGLRender
{
// #include "RenderDeclaration.h"
void SetupScreen();
void ClearScreen();
void UpdateScreen();
};
^ А затем уже линковщик подловит все обьявления функций с их реализациями в OpenGLRender.cpp и все будет хорошо
Но хорошо, вы скажите, это не гибко и вообще очень плохо. Но я вас спрошу: "Какая, черт побери, гибкость в фундаменте архитектуры, которая ну никак не меняется?!"
По сути, виртуализация - это очень тяжелая штука. Каждая виртуальная функция уже КАК МИНИМУМ занимает от 4 до 8 байт! (4 байта на 32 битной машине. 8 байт на 64 битной машине. Но не суть)
Например вы пишете движок, вы 1 раз реализовали класс для определенной графики - и забыли. Вам не нужно каждый раз менять что-то, особенно динамично - это не имеет смысла так такового (а оверхед будет иметь)
"А если человек хочет реализовать свой вариант графики?" - тогда он просто создаст новый класс, подключит файл с функциями, IDE ему сразу предложит/подскажет какие функции надо реализовать - реализуете и работаете. Все! А чтобы применить графику, достаточно (к примеру):
// Config.h
#define RENDER_CLASS ROpenGLRender
А затем, уже где-то под капотом движка:
// Engine.cpp
#include "Config.h"
void Engine::SetupRender()
{
RENDER_CLASS RenderClass;
RenderClass.SetupScreen();
RenderClass.ClearScreen();
RenderClass.UpdateScreen();
/* Other... */
}
И, если кто не понял, при проходе препроцессингом RENDER_CLASS заменится на ROpenGLRender и мы получим строку ROpenGLRender RenderClass;
И да, если я создам класс RVulkanRender, реализую функции, обновлю конфиг как #define RENDER_CLASS RVulkanRender, то получу тот же гибкий функционал при минимальных затратах. Никаких виртуальных функций, виртуальных таблиц и прочего
А в завершении могу добавить: При обновлении движка, создателю достаточно добавить новое обьявление в RenderDeclaration.h, а затем пользователь (работающий на движке) просто дополнит свой класс RVulkanRender новой функцией и все будет как раньше - без всякого "ой, я случайно забыл переопределить функцию"
What you don't use, you don't pay for. Think Cold.
❤4👍2🔥1👀1
Теория многопоточности - это просто
И я серьёзно: кто хочет вкатиться в теорию многопоточности - не поленитесь и почитайте эту шикарную статью на Хабре:
https://habr.com/ru/articles/974198/
И я серьёзно: кто хочет вкатиться в теорию многопоточности - не поленитесь и почитайте эту шикарную статью на Хабре:
https://habr.com/ru/articles/974198/
❤1🔥1🤩1💯1
RootSAI - Simple Assembler Interpreter
I use assembler btw
На днях написал свой простой интерпретатор виртуального 8-битного процессора на плюсах
Проект вышел небольшой, хотя разрабатывать было жуть как интересно
Внутри: 8 регистров, 15 инструкций и моя фирменная архитектура для масштабируемости 🤌
И да, я не полностью воссоздаю архитектуру какого-либо процессора. Проект служит чисто в образовательных целях, а также быть оптимизированным под запуск на настоящем 8-битном AVR 💀
Ссылка: https://github.com/RootTool0/RootSAI
I use assembler btw
На днях написал свой простой интерпретатор виртуального 8-битного процессора на плюсах
Проект вышел небольшой, хотя разрабатывать было жуть как интересно
Внутри: 8 регистров, 15 инструкций и моя фирменная архитектура для масштабируемости 🤌
И да, я не полностью воссоздаю архитектуру какого-либо процессора. Проект служит чисто в образовательных целях, а также быть оптимизированным под запуск на настоящем 8-битном AVR 💀
Ссылка: https://github.com/RootTool0/RootSAI
GitHub
GitHub - RootTool0/RootSAI: RootSAI - Simple Assembler Interpreter
RootSAI - Simple Assembler Interpreter. Contribute to RootTool0/RootSAI development by creating an account on GitHub.
❤3🔥1
С++ тян
теперь вы видели все
Перевод:
- Эй, С++. Можешь ли ты скомпилировать этот код для меня?
- Нет проблем, одну минуту, давай я проверю твой код... Ох~.. Ты правда хочешь сделать это, хах?
- Сделать что? Какие-то проблемы в моём коде?
- Нет-нет, все в порядке! Ноль синтаксических ошибок в коде, то что нужно для меня! Держи свой .exe файл
- Отлично, рад слышать. Спасибо большое
В консоли. Пытается запустить программу
- Ну давай-же... Оно должно работать...
- 🤛 SEGMENTATION FAULT
^ Критическая ошибка программы, когда она пытается получить доступ к памяти, к которой не имеет права. Обычно это разыменование нулевого указателя, или же, выход за границы массива
теперь вы видели все
Перевод:
- Эй, С++. Можешь ли ты скомпилировать этот код для меня?
- Нет проблем, одну минуту, давай я проверю твой код... Ох~.. Ты правда хочешь сделать это, хах?
- Сделать что? Какие-то проблемы в моём коде?
- Нет-нет, все в порядке! Ноль синтаксических ошибок в коде, то что нужно для меня! Держи свой .exe файл
- Отлично, рад слышать. Спасибо большое
В консоли. Пытается запустить программу
- Ну давай-же... Оно должно работать...
- 🤛 SEGMENTATION FAULT
^ Критическая ошибка программы, когда она пытается получить доступ к памяти, к которой не имеет права. Обычно это разыменование нулевого указателя, или же, выход за границы массива
❤🔥3💋2❤1
Оптимизация bool и битовые поля
Господа, сегодня в нашем чате выяснилась неприятная новость - вы не знаете как оптимизировать bool?
Обьясняю на пальцах:
Начиная с первого стандарта С++98 (тык) тип bool определен как целочисленный тип, размер которого определяется реализацией (implementation-defined) и на большинстве современных платформ равен 1 байту, то есть: sizeof(bool) = 1 байт
Но логичный вопрос: Если для true и false нужен лишь 1 бит, то куда остальные 7 бит деваются? НИКУДА
7 бит банально "простаивают", не используются.
Скажете фигня? Так-то да, но есть и более низкоуровневые вещи, где это явно проявляется - видеокарта
В любом игровом движке есть внегласная цель: убить время в общении между CPU и GPU. Это синхронизации, перевод команд, общение - все это занимает уйму времени (а я напомню - мы должны выдать как минимум*60 кадров в секунду, при этом успеть просчитать движковые компоненты, акторы мира, UI, звуки, кнопки, и зарендерить это все)
И один из способов ускорить общение CPU и GPU - банально сжать данные для передачи по шине, чтобы уменьшить количество передаваемых байт. И именно тут bool вставляет палки в колеса: Создать 32 переменных bool - это 32 байта. А если использовать оптимизированный вариант - всего-лишь 4 байта. Чувствуете разницу? Данные сжались в 8 раз!
Теперь про сам способ (не является серебрянной пулей, но иногда выигрывает)
Битовые поля
^ Здесь ": 1" и тд. - указывает количество бит, выделенных для данной переменной. В нашем случае a - 1 бит, b - 3 бита, c - 4 бита. Замерив размер структуры через sizeof(S) на большинстве компиляторов и платформ это даст 1 байт. 1 байт! Но мы в него впихнули 3 переменных!
И это не конец, ведь, можно создать 8 переменных по 1 биту, и тем самым, упакуем 8 переменных в 1 байт. А вспоминая, что bool и так использует 1 бит для работы, то получается мы 8 bool-переменных упаковали в 1 байт, вместо 8!
Оптимизация? Оптимизация. И если кто считает чересчур бредом - взгляньте исходники Unreal Engine. У него во всех горячих местах используется этот простой синтаксис
Use every bit for your purposes. Think Cold.
Господа, сегодня в нашем чате выяснилась неприятная новость - вы не знаете как оптимизировать bool?
Обьясняю на пальцах:
Начиная с первого стандарта С++98 (тык) тип bool определен как целочисленный тип, размер которого определяется реализацией (implementation-defined) и на большинстве современных платформ равен 1 байту, то есть: sizeof(bool) = 1 байт
Но логичный вопрос: Если для true и false нужен лишь 1 бит, то куда остальные 7 бит деваются? НИКУДА
7 бит банально "простаивают", не используются.
Скажете фигня? Так-то да, но есть и более низкоуровневые вещи, где это явно проявляется - видеокарта
В любом игровом движке есть внегласная цель: убить время в общении между CPU и GPU. Это синхронизации, перевод команд, общение - все это занимает уйму времени (а я напомню - мы должны выдать как минимум*60 кадров в секунду, при этом успеть просчитать движковые компоненты, акторы мира, UI, звуки, кнопки, и зарендерить это все)
И один из способов ускорить общение CPU и GPU - банально сжать данные для передачи по шине, чтобы уменьшить количество передаваемых байт. И именно тут bool вставляет палки в колеса: Создать 32 переменных bool - это 32 байта. А если использовать оптимизированный вариант - всего-лишь 4 байта. Чувствуете разницу? Данные сжались в 8 раз!
Теперь про сам способ (не является серебрянной пулей, но иногда выигрывает)
Битовые поля
struct S {
uint8_t a : 1;
uint8_t b : 3;
uint8_t c : 4;
};^ Здесь ": 1" и тд. - указывает количество бит, выделенных для данной переменной. В нашем случае a - 1 бит, b - 3 бита, c - 4 бита. Замерив размер структуры через sizeof(S) на большинстве компиляторов и платформ это даст 1 байт. 1 байт! Но мы в него впихнули 3 переменных!
И это не конец, ведь, можно создать 8 переменных по 1 биту, и тем самым, упакуем 8 переменных в 1 байт. А вспоминая, что bool и так использует 1 бит для работы, то получается мы 8 bool-переменных упаковали в 1 байт, вместо 8!
Оптимизация? Оптимизация. И если кто считает чересчур бредом - взгляньте исходники Unreal Engine. У него во всех горячих местах используется этот простой синтаксис
Use every bit for your purposes. Think Cold.
❤3🔥2😱1
Shoko - Compile-time UI Framework
В общем, чтобы не переполнять данный блог лишним контентом(которого и так здесь не бывает)
Завел отдельный блог для своего фреймворка: Shoko - UI Framework
Блог не будет стремиться к финальному продукту, это просто.. разработка. Такая, какая она есть - со всем своим ужасом и красотой
Да, будет больше живых, "нетехничных", моментов, а также слишком заумные штуки
Так что кто желает - приглашаю присоединиться к своему ответу на вопрос "Как далеко можно зайти, перенося Runtime на Compile-time?"
Ссылочка: тык
В общем, чтобы не переполнять данный блог лишним контентом
Завел отдельный блог для своего фреймворка: Shoko - UI Framework
Блог не будет стремиться к финальному продукту, это просто.. разработка. Такая, какая она есть - со всем своим ужасом и красотой
Да, будет больше живых, "нетехничных", моментов, а также слишком заумные штуки
Так что кто желает - приглашаю присоединиться к своему ответу на вопрос "Как далеко можно зайти, перенося Runtime на Compile-time?"
Ссылочка: тык
Telegram
Shoko - UI Framework
Shoko - Compile-time UI Framework
https://github.com/RootTool0/Shoko
https://github.com/RootTool0/Shoko
💯2
С НОВЫМ ГОДОМ!
Я хочу от всей души поблагодарить всех вас, кого встретил, и кто остался со мной
Хочется вот просто обнять всех! И сказать вот что:
Атом - Бро, мы с тобой сколько уже прошли? Брат за брата как 2 солдата - и в снег, и в град, и в Демо, и в Релиз
Денчик - тот самый, мой любимый 🤪 😋. Люблю, уважаю, и просто рад что встретил тебя
мдпка - жжешь! Просто в соло поднялся и в музыке, и в C#. А вообще - ты красавчик, растешь на глазах, и мотивируешь меня
Оранж - Ну просто наш крепкий политик и специалист в монолитности кода)) Рад что встретил тебя, дружище!
Матвейка - Любимый кот Шредингера, хотя стоит тебе просто определится с языком программирования и все пойдет в гору
Котомаг - И ссоримся, и миримся, и скидываем друг-другу ДЗ по Алгебре и арты по ZZZ - Все стабильно, а стабильность - залог успеха
И одна милая девушка - Что нашла меня под мое грустное настроение перед моим ДР, и теперь которую я рад менторить по С++. Я рад что встретил тебя
Еще раз обнимаю всех вас, ребятки ;)
Я хочу от всей души поблагодарить всех вас, кого встретил, и кто остался со мной
Хочется вот просто обнять всех! И сказать вот что:
Атом - Бро, мы с тобой сколько уже прошли? Брат за брата как 2 солдата - и в снег, и в град, и в Демо, и в Релиз
Денчик - тот самый, мой любимый 🤪 😋. Люблю, уважаю, и просто рад что встретил тебя
мдпка - жжешь! Просто в соло поднялся и в музыке, и в C#. А вообще - ты красавчик, растешь на глазах, и мотивируешь меня
Оранж - Ну просто наш крепкий политик и специалист в монолитности кода)) Рад что встретил тебя, дружище!
Матвейка - Любимый кот Шредингера, хотя стоит тебе просто определится с языком программирования и все пойдет в гору
Котомаг - И ссоримся, и миримся, и скидываем друг-другу ДЗ по Алгебре и арты по ZZZ - Все стабильно, а стабильность - залог успеха
И одна милая девушка - Что нашла меня под мое грустное настроение перед моим ДР, и теперь которую я рад менторить по С++. Я рад что встретил тебя
Еще раз обнимаю всех вас, ребятки ;)
if(std::time(nullptr) > 1767214800)
std::cout << "New Year 2026!";
❤4❤🔥1💯1🎄1