𝐑𝐨𝐨𝐭𝐓𝐨𝐨𝐥 𝐁𝐥𝐨𝐠
194 subscribers
570 photos
48 videos
5 files
60 links
ニャン
Download Telegram
Forwarded from Nothing To Show
Media is too big
VIEW IN TELEGRAM
Вспомнил капкат и решил смонтажить что-то (спасибо RootTool за перевод)
👏3🔥1💋1
This media is not supported in your browser
VIEW IN TELEGRAM
❤️ - Visual Studio Code
🔥 - Rider IDE
👀 - notepad.exe
🔥9❤3👀3
Скоро уже 20 лет....
❤6😢1🫡1
Доброе утро
❤5🥰2😁1
Выравнивание данных (Data Alignment) в C++
#новичкам

Не сказать что тема прям супер-важная, но дает глубокое понимание работы с памятью в С++.

Начнем с основы: Стек - Область оперативной памяти, в которой хранятся временные переменные во время работы вашей программы. Процессор подгружает эти переменные из стека в свой кеш и работает с ними (производит какие-либо операции и тд.)
P.S. Я знаю, обьяснено крайне поверхностно, не бейте

Но стек подгружается в кеш блоками, то есть, за 1 такт считывает определенную область с стека в кеш и работает с ней. Обычно оно кратно 4/8/16/32/64 (Зависит от архитектуры процессора и настроек компилятора) и тема "Выравнивание данных" как раз про это

В теории: Для правильной подгрузки компиляторы обычно выравнивают данные структур под четкую размерность (MSVC: 8 байт для x64 и 4 байт для x32) чтобы не было долгой подгрузки частями (что замедляет работу и может привести к исключениям-). И именно тут все зависит от программиста, ведь правильное размещение полей структуры напрямую влияет на производительность и корректность программы (оптимизация ура)

На практике: Рассмотрим структуры FGoodStructure и FBadStructure. Обе имеют одинаковое количество информации, по идее и размер (8+4+2+1 = 15 байт) должен быть одинаковым, так? Не совсем: Узнав размер структуры через функцию sizeof() выяснится неприятная новость - FBadStructure имеет размер 24 байт, в то время как FGoodStructure только 16

Почему так? Ответ в выравнивании - процессору удобно обращаться к определенному типу данных по адресу, кратному 4 (или 8). И в данном случае в FBadStructure имеет плохое расположение полей - int SomeInt (4 байт) попросту не уместить рядом с char SomeChar (1 байт) - компилятору НУЖНО вставить 3 пустых байта между ними для выравнивания. И да, это фича, с вытекающими ввиде раздутого размера структуры

А для лучшего понимания давайте лучше визуализируем (и нет, это не придумано мною, буквально программа сама выдает этот результат). Как видите между SomeInt и SomeChar стоит 3 байта для выравнивания, а после SomeNumber аж 6 пустых байт. Безумие? Ага. Но зато какое. При этом у FGoodStructure реально все хорошо. Всего-лишь 1 пустой байт для выравнивания размера к кратному 8 (в данном случае размер 15 байт ближе к 16 вместо 24 :D)

Смысл басни такова: Прописывайте свои поля в структуре так, чтобы размеры их типов шли от большего к меньшему (как в примере FGoodStructure). Это легко, это просто, это эффективно. Программу не сломает, а процессор спасибо скажет

Aligment Your Structures. Think Cold.
❤4🔥2👍1🆒1
Была значит у меня на часах Акира....

не спрашивайте что я делал с ней 🤫
😁3🤯1
XP, 7-ка, к вам новый друг пришел...
🙏5😭3🕊1
Есть 2 стула...
🔥3😁3❤2🍾1
𝐑𝐨𝐨𝐭𝐓𝐨𝐨𝐥 𝐁𝐥𝐨𝐠
Неожиданный дроп, месяц работы и встречайте - A Cold Love Story Remaster (V1.1) Да-да, хоть кто-то спустя 10 лет взялся за игру Лиама Викерса (Серьезно, он выпустил ее в 2015-м) Чем можем порадовать? - Подчистка от лишних файлов - залог оптимизации (Вес…
Еще больше и неожиданнее дроп - A Cold Love Story Remaster V1.2

В данном обновлении мы добавили сразу 3 оригинальные истории связанные с этой новеллой:
- ACLS Reload (ХИЛ Перезапуск)
- ACLS Retold [1/2] (Пересказ ХИЛ [1/2])
- ACLS Retold [2/2] (Пересказ ХИЛ [2/2])

Все они имеют оригинальный-английский и русский-переведенный вариант (Переводчик: Ponder_Static)

P.S. Пересказанные истории являются тем же рассказом, но от лица Сары - лично мне понравилось читать их. Кого заинтересовал - бегом скачивать!

Ссылочка: тык
(Windows/Linux/Android)
❤‍🔥4🔥1
Искал гайд про работу с Enum, а нашел большую статью про внутреннюю работу всей рефлексии в Unreal Engine

Рефлексия - способность программы обновлять данные о классе, не выходя из нее. В данном случае: Программист пишет код, создает переменную, компилирует, а UE в свою очередь обновляет интерфейс редактора, добавляя туда эту переменную, поля, кнопочки к ней и тд.

Удобно же ведь!
(ага, если бы не тупила вообще супер :D)

Ах да, та самая статья на Хабре: https://habr.com/ru/articles/690662
🔥3❤‍🔥1🤩1
4. друг PHP
5. преподаёт в школе
6.
❤‍🔥4🤩1
А на чей стороне ты?
❤4❤‍🔥1🤩1
Искусство Построения Архитектуры Проекта

Пролог

Как однажды говорил Линус Торвальдс: «Плохие программисты беспокоятся о коде. Хорошие программисты беспокоятся о структурах данных и отношениях между ними»

И с ним я солидарен. Сеньоров тем и отличаются, что они не просто пишут для "сейчас", а продумывают архитектуру "на перед", на месяцы и годы, чтобы любое обновление не заставляло ломать весь код и наращивать костыли.

В данной серии постов я расскажу про свой опыт и советы по построения хорошей архитектуры, ведь это является фундаментом и скелетом всего вашего проекта.

Сразу оговорюсь: Я не вешаю себе корону и не считаю себя 100% сеньором как таковым. Хоть и знаю про построение архитектур, имею опыт, прописываю весь бекенд и документации к нему, но опять же: В своей команде Portal: Solver - я один-единственный программист. Так что формально команда есть, но из моей области - только я. И конечно в одиночку кричать что я сеньор - глупо...

Get Ready. Think Cold.
❤3🔥1💯1
This media is not supported in your browser
VIEW IN TELEGRAM
Искусство Построения Архитектуры Проекта

Глава 0: Реализация функций

Перед прочтением стоит упомянуть что такое "Реализованные функции" ?
Когда вы пишите:
int Foo(int a, int b) {
return a + b;
}

^ Это является реализованной функцией, ведь вы объявили ее: "int Add(int a, int b)" и сразу реализовали тело функции: "return a + b;" - так компилятор сразу может объявить функцию Add и скомпилировать ее "внутрянку" в машинный код

А нереализованная функция выглядит примерно так:
int Foo(int a, int b);

^ Вы знаете что внутри этой функции? Вот и компилятор не знает что там! А поэтому не может скомпилировать ее в машинный код (ведь он не знает что внутри ¯\_(ツ)_/¯) - это и есть нереализованная функция

Оговорка: В стандарте С++ корректнее называть "объявление функции", но в данной серии постов мы будем использовать глагол "объявить" как "создание переменной/функции. Просто очерк в коде, что она есть", а под словом "реализация" будем иметь ввиду "прописывание тела функции"

Implement Your Functions. Think Cold.
❤3❤‍🔥1💯1
Искусство Построения Архитектуры Проекта

Глава 1: Аксиома Компиляции

Еще с самых основ в С/C++ была идея компиляции такова: Каждый .c/.cpp файл с кодом компилируется в промежуточный файл компиляции с расширением .o/.obj, а затем линковщик (линкер) соединяет их все вместе в единый бинарный файл

На будущее: Мы будем работать с Unreal Engine на С++ и ОС Windows, поэтому, нам будет привычнее говорить про форматы .cpp и .obj соответственно

Если не углубляться в стандартный С++, то грубо говоря: Сколько .cpp - столько и .obj

Но что хранит в себе .obj файл? По сути информацию о функциях/переменных и скомпилированный код:
- Машинный код функций - Скомпилированный вариант реализованных функций на ассемблере
- Таблицу символов - Какие переменные и функции объявлены в этом .cpp файле
- Список неразрешенных символов - Какие функции НЕ реализованы в данном файле (лишь объявлены)

Затем на очередь идет линковка. Линкер берет все .obj файлы и соединяет их воедино, сопоставляя все нереализованные функции с их реализациями и собирая все в один финальный бинарный файл (бинарник)

Такая механика позволяет, например, изменить 1 .cpp файл, который превратится в 1 .obj файл, а затем достаточно сделать линковку этого нового файла с другими файлами (.obj) и получить тот же бинарник, не перекомпилируя все .cpp файлы. Удобно как никак!

Теперь вы знаете суть компиляции. Помните эту концепцию - еще не раз вернёмся к ней ;)

Know Your Compiler. Think Cold
❤2🔥1🤩1
This media is not supported in your browser
VIEW IN TELEGRAM
❤‍🔥1🤩1
Искусство Построения Архитектуры Проекта

Глава 2: Препроцессор

Препроцессор как квантовая физика: "Если вы понимаете препроцессор, значит вы его не понимаете"

Его легко понять, но в то же время нужно учитывать множество вещей. Но начнем с основ. Что делает этот ваш препроцессор ? По сути: Он преобразует удобный для человека код в форму, понятную компилятору. Наверняка вы слышали такие директивы как: #include, #define, #if, #else, #endif, #ifdef, #pragma once, #pragma region/endregion и другие...

Результатом препроцессора является Единица Трансляции (TU - Translation Unit) - это тот-же исходный код .cpp файла, но со всеми включенными заголовочными файлами (#include), раскрытыми макросами (#define) и обработанными условиями (#if, #else, #endif, #ifdef). Получившийся текст передается компилятору.

Препроцессор запускается перед компиляцией кода, и с ним вполне удобно работать. Расскажу про базовые директивы, с которыми лично я имею дело:

- #include "Path" - Берет файл из этого пути, просто копирует его содержимое и вставляет его вместо себя. То есть буквально вставляет содержимое одного файла в другой (до компиляции). Пример:

Что видит человек:
// main.cpp

#include "MathUtils.h"

int main() {
int a = 5, b = 3;
int sum = Add(a, b);
return sum;
}

// MathUtils.h

int Add(int x, int y) {
return x + y;
}


Что видит компилятор:

// На месте, где был #include "MathUtils.h"
int Add(int x, int y) {
return x + y;
}
// Он грубо вставляет код с файла MathUtils.h

int main() {
int a = 5, b = 3;
int sum = Add(a, b);
return sum;
}


- #define - Те самые "макросы". По сути это слепая вставка частей кода. Традиционно используется для констант и повторяющихся блоков кода, НО, в то же время имеет непредсказуемость из-за своей специфики. Как говорится: Используете, но с осторожностью. Пример:

Что видит человек:
#define PI 3.14
#define RADIUS 2.0
float Length = 2 * RADIUS * PI;
float Area = PI * RADIUS * RADIUS;


Что видит компилятор:
float Length = 2 * 2.0 * 3.14;
float Area = 3.14 * 2.0 * 2.0;


- #if, #else, #endif, #ifdef - Условная компиляция. Позволяет включать/исключать куски кода по условию. Крайне полезная штука

- #pragma region/endregion - Не стандартные С++ директивы (Но поддерживаются в Visual Studio, Rider, CLion и другие). Сделаны чисто для визуального "сворачивания" кода в области/регионы. Опять же - созданы только для IDE, никак не влияют на компиляцию (чисто косметическая функция).

Про #pragma once поговорим в следующей главе

Главная изюминка препроцессора: Он никак не входит в бинарник и не добавляет лишнего веса (если только вы сами не создадите макросы, которые генерируют дополнительный код), а также он больше ориентирован (имеет большой арсенал макросов) для получение информации с системы, компилятора, окружения и тд.

Так, например, можно узнать информацию о:
- Компиляторе - MSVC, MinGW, GCC и другие
- ОС - Windows, Linux, macOS и тд.
- Какой тип сборки - Debug, Release
А в контексте Unreal Engine:
- Какая целевая сборка проекта - Development, DebugGame, Shipping

На этом теоретическая часть подходит к концу. Хотел сделать главу 3 про единицы трансляции, но она такая мелкая, что легче ее здесь расписать. В следующей главе уже поговорим про Forward-Declaration и заголовочные (.h) файлы

See the Code Before the Compiler. Think Cold.
❤2🔥1