#HEX • IT – Telegram
#HEX • IT
369 subscribers
501 photos
104 videos
64 files
478 links
Channel by @alexeev_dev.

Авторский блог.

IT, статьи и другая информация.
Download Telegram
https://habr.com/ru/companies/timeweb/articles/971528/

Четвертая часть серии статей про трюки на си!

В этой статье будет еще больше всевозможных генераторов псевдослучайных чисел, гонок за скоростью и производительностью, алгоритмов, хаков и трюков!

Вот и наступила 4 часть! В этой статье мы погружаемся в менее известные хаки, фаны, алгоритмы на нашем любимом живом C!
3👍2❤‍🔥1
#HEX • IT pinned «https://habr.com/ru/companies/timeweb/articles/971528/ Четвертая часть серии статей про трюки на си! В этой статье будет еще больше всевозможных генераторов псевдослучайных чисел, гонок за скоростью и производительностью, алгоритмов, хаков и трюков! Вот…»
Идиома RAII (Resource Acquisition Is Initialization)

В среде разработчиков C++ широко используется идиома RAII (Resource Acquisition Is Initialization). Её суть заключается в автоматизации управления жизненным циклом ограниченных ресурсов вычислительной системы (таких как память, файловые дескрипторы, сетевые соединения).

Типичный жизненный цикл ресурса включает три этапа:
1. Захват ресурса (выделение памяти, открытие файла, установка соединения).
2. Использование ресурса (операции чтения/записи, передача данных).
3. Освобождение ресурса (возврат памяти системе, закрытие дескриптора).

Идиома RAII гарантирует корректное освобождение ресурсов путём привязки их жизненного цикла к времени существования объектов C++. Это достигается через:
- Конструктор → захват ресурса
- Методы класса → использование ресурса
- Деструктор → автоматическое освобождение ресурса

При уничтожении объекта (например, при выходе из области видимости) ресурс гарантированно возвращается системе. Это исключает утечки ресурсов, критичные для долгоживущих приложений.

Примеры из стандартной библиотеки C++:

1. std::unique_ptr — эксклюзивное владение ресурсом:
{
std::unique_ptr<int> ptr(new int(42)); // Выделение памяти (захват)
*ptr = 10; // Использование ресурса
} // Память автоматически освобождается (деструктор)


2. std::shared_ptr — разделяемое владение:
{
auto ptr1 = std::make_shared<double>(3.14); // Захват ресурса
{
auto ptr2 = ptr1; // Копирование указателя
std::cout << *ptr2; // Использование
} // ptr2 уничтожается, ресурс сохраняется
} // ptr1 уничтожается → ресурс освобождается


Пользовательский класс RAII для работы с файлами:
class FileHandler {
public:
explicit FileHandler(const std::string& path)
: file_(std::fopen(path.c_str(), "r")) // Захват ресурса
{
if (!file_) throw std::runtime_error("File open error");
}

void write(const std::string& data) {
if (std::fputs(data.c_str(), file_) == EOF) {
throw std::runtime_error("Write error");
}
}

~FileHandler() {
if (file_) std::fclose(file_); // Освобождение ресурса
}

// Запрещаем копирование
FileHandler(const FileHandler&) = delete;
FileHandler& operator=(const FileHandler&) = delete;

private:
FILE* file_;
};

// Использование:
{
FileHandler file("data.txt"); // Открытие файла
file.write("Hello RAII"); // Запись данных
} // Файл автоматически закрывается


Ключевые преимущества подхода:
1. Детерминированное освобождение — ресурсы возвращаются сразу при выходе объекта из области видимости.
2. Исключение безопасности — корректная обработка исключений благодаря стековой раскрутке.
3. Инкапсуляция — логика управления ресурсом изолирована внутри класса.
4. Устранение ручного управления — исключены ошибки забытого освобождения ресурсов.
🔥2👍1
Джин

Однажды Линус Торвальдс шёл по пляжу, думал о том, что мы все живём в матрице, и грустно смотрел под ноги. В песке он заметил бутылку, подозрительно похожую на коньяк, и возрадовался. Но при ближайшем рассмотрении бутылка оказалась непрозрачной, с сургучной печатью, на которой проступал религиозный символ страны, с которой сложные отношения.

Линус конечно же применил брутфорс и открыл бутылку, из которой немедленно вылез джинн.

— Значит так, у тебя есть три желания, — сообщил джинн. — Но нельзя желать, чтобы кто-то умер, нельзя желать, чтобы кто-то влюбился в тебя, и нельзя желать больше желаний.

— А меньше желаний желать можно? — уточнил Линус, продолжая думать про матрицу.

Джин озадачился, почесал в затылке и решил, что можно.

— Тогда я хочу чтобы количество моих желаний уменьшилось на три.

— Зачем? — поинтересовался джинн.

— Потому что я думаю, что ваши джинновые серверы записывают количество желаний в целочисленные переменные и не хранят информацию об отрицательных значениях, так что когда количество моих желаний уменьшится на три, оно станет равно нулю, после чего тебе нужно вычесть ещё единицу за то желание, которое только что исполнилось, переменная переполнится и количество моих желаний станет равно максимальному возможному значению.

— Слушай, я из 900-х годов до нашей эры, я не понимаю, — покачал головой джинн. — Меня как царь Соломон запечатал сюда, я выпал из новостной ленты совершенно.

— Ты просто сделай так, как я говорю, — посоветовал Линус.

Джинн вырвал жменьку волос из бороды, пошептал, поводил руками в воздухе, и ничего не произошло. Тогда он достал из широких шаровар записной свиток из папируса.

— У тебя теперь три желания, — прокомментировал он, сверившись с папирусом.

— O shit, — удивился Линус.

— Но вообще довольно здорово, — попытался ободрить его джинн. — Я никогда раньше не видел, чтобы человек загадал желание, и у него осталось столько же желаний. Даже если бесполезное. Хороший фокус для вечеринок.

— Двухбитная переменная, — удивился Линус. — Необычно.

— Может, дворец? — сочувственно предложил джинн. — Миллион динаров? 72 девственницы? Я могу, если что...

— Я хочу, чтобы переменная, хранящая информацию о доступных мне желаниях, стала 16-битной, определился Линус.

— Я всё ещё не понимаю, — покачал головой джин. — 900-е годы. До нашей эры.

— Это ничего, — ответил Линус, привыкший иметь дело с гуманитариями. — Ты просто сделай то что я сказал, слово в слово.

Джинн вырвал волоски из брови, пошептал, поводил руками, и снова ничего не произошло. Он снова сверился с папирусом.

— У тебя теперь два желания, — развёл руками он.

— А вот теперь я хочу, чтобы у меня стало на два желания меньше.

Джинн вырвал волоски из подмышки, поколдовал и посмотрел в папирус.

— У тебя 65 535 желаний, — озадаченно сказал он.

Линус Торвальдс нехорошо улыбнулся.

— Я же говорил, что мы живём в матрице. Присаживайся. Записывай. Значит, во-первых...
😁9🤣31
me cleaner

me cleaner — это Python-скрипт, предназначенный для модификации прошивки Intel Management Engine (ME) с целью снижения её взаимодействия с системой.

Intel ME, присутствующий на большинстве материнских плат Intel с 2006 года, выполняет функции, требующие полного доступа к системе, однако его прошивку невозможно полностью отключить или удалить с 2008 года без последствий.

me cleaner предлагает решение, позволяющее оставить Intel ME активным только в процессе загрузки, а затем отключить его во время обычной работы.

Скрипт совместим с большинством платформ Intel.

https://github.com/corna/me_cleaner
🔥3👍1
Forwarded from Хабр
Тёмная сторона Си: битовая магия и запрещённые приёмы

Чистый код и безопасные практики — это фундамент индустрии, но иногда хочется заглянуть в бездну «ненормального» программирования. Там, где заканчиваются стандарты, начинаются битовые сдвиги вместо арифметики, сверхбыстрые генераторы псевдослучайных чисел и агрессивная оптимизация на грани фола.

Этот материал — экскурсия по алгоритмическим аномалиям. Разберём примеры, которые не несут прямой бизнес-ценности, но отлично тренируют понимание низкоуровневых процессов и работы памяти.
3👍1
Интерпретатор Python, написанный на Python в 500 строк кода

Byterun - это интерпретатор Python. Работая над Byterun, автор обнаружил, что фундаментальная структура интерпретатора Python легко укладывается в ограничение на размер в 500 строк. В этой статье рассмотрена структура интерпретатора и дан контекст для его дальнейшего изучения.

 Цель не в том, чтобы объяснить все, что нужно знать об интерпретаторах, - как и во многих других интересных областях программирования и информатики, - вы можете посвятить годы глубокому пониманию этой темы.

Byterun был написан Недом Батчелдером, опираясь на работу Пола Шварца. Его структура похожа на основную реализацию Python, CPython, поэтому понимание Byterun поможет вам понять интерпретаторы в целом и интерпретатор CPython в частности. (Если вы не знаете, какой Python вы используете, то, скорее всего, это CPython). 

Статья: https://aosabook.org/en/500L/a-python-interpreter-written-in-python.html
Github: https://github.com/nedbat/byterun
🔥4👍32
Paged Out! - это бесплатный англоязычный технический журнал о хакинге, трюках и программировании в формате одна страница = одна статья.

Журнал курируется сообществом и полностью бесплатный

Журнал принимает также заявки на статьи: https://pagedout.institute/?page=cfp.php

Ссылка на сайт: https://pagedout.institute/
1🔥32
https://pshenok.github.io/server-survival/

Довольно залипательная игра,позволяющая прокачать system design.

Игра в жанре tower defence, где мы управляем серверной инфраструктурой.
🔥3❤‍🔥1😁1
PEP-799: Семплирующий профилировщик встроенный в Python 3.15+

Краткий обзор: https://docs.python.org/3.15/whatsnew/3.15.html#whatsnew315-sampling-profiler
Документация: https://docs.python.org/3.15/library/profiling.sampling.html

Кратко:
- В 3.15 cProfile (написан на C) был перемещен в profiling.tracing
- В 3.15 profile (написан на Python) стал deprecated, его уберут в 3.17
- Добавили новый profiling.sampling (кодовое имя `tachyons`), о нем и поговорим
- А еще добавили встроенные TUI (на скриншоте) и GUI

Ключевые фичи:
- Almost Zero-overhead: добиваемся такого, за счет того, что переодически получаем готовые стектрейсы работающих процессов, не нужно добавлять инструментацию функций как в cProfile
- Не нужно менять существующий код
- Разные режимы работы: attach позволяет подключиться к работающему Python процессу, а run позволяет запустить код для профилировки
- Разные виды замеров: --mode wall, --mode cpu, --mode gil, --mode exception
- Поддержка тредов
- Поддержка asyncio с флагом --async-aware, можно смотреть даже suspended tasks с --async-mode=all
- Разные форматы вывода информации: --flamegraph, --pstats, --heatmap, --gecko
- --live вместе с TUI для отображения информации в реальном времени (как в top условном)
- Поддержка профилирования до уровня опкодов виртуальной машины, включая специализации
- Гибкая конфигурация буквально всего

Примеры запуска:
- python -m profiling.sampling run --flamegraph -o profile.html noscript.py - запускаем скрипты и генерим флеймграф
- python -m profiling.sampling attach --live $YOUR_PID - профилируем работающий процесс и получаем данные в реальном времени

На чем основана работа технически?

- PEP-768 с remote-debugging предоставляет техническую возможность быстро и легко получать семплы из виртуальной машины
- Для asyncio используется новый АПИ для async-aware call-graphs

Личное мнение: очень крутая фича, пока у меня вопросы по TUI / GUI. Не очень понимаю, зачем их затащили в stdlib. Зарепортил пару багов. На маке требуется запускать профилировщик с sudo -E. Остальное - нравится!
Кирилл вот тоже заценил.

Обсуждение: Что вы думаете о данной фиче? Как вы сейчас профилируете ваши приложения в разработке и в проде?

P.S. Последний пост в текущем году. Всех с наступающим! 🎄

| Поддержать | YouTube | GitHub | Чат |
1👍1🔥1
#HEX • IT pinned «https://habr.com/ru/companies/timeweb/articles/971962/ Вышла 5, юбилейная часть серии статей про трюки на си! В этой статье будет еще порция свежих хаков, фанов, трюков, еще больше магии и скорости!»
BusyBox — набор UNIX-утилит командной строки, представленный в виде единого исполняемого файла. Разработан в 1996 году Брюсом Перенсом.

Особенности:

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

BusyBox — двоичный файл с несколькими вызовами. Существует только один исполняемый файл, но он действует как несколько служебных программ (апплетов). Это позволяет уменьшить размер BusyBox, поскольку все встроенные служебные программы могут использовать общий код для многих распространённых операций.

Вызвать BusyBox можно, введя команду в качестве аргумента в командной строке. Также можно использовать ссылки на двоичный файл BusyBox: например, ввод ln -s /bin/busybox ls ./ls заставляет BusyBox вести себя как команду ls (если команда ls была скомпилирована в BusyBox).

Busybox можно использовать в эмбеддед устройствах, загрузочных средах (многие могли столкнуться с ним во время фикса очередной проблемы загрузки). А также busybox используют минималистичные системы, например Tiny Core Linux (на хабре есть интересная статья о нем). Он воплощает философию Unix "делай одну вещь и делай ее хорошо", но на мета-уровне: сам BusyBox — это единый инструмент, который предоставляет множество инструментов, оставаясь при этом минималистичным, эффективным и универсальным решением для ситуаций, где каждый байт имеет значение.
1🔥42👍1
#HEX • IT
https://habr.com/ru/companies/timeweb/articles/971962/ Вышла 5, юбилейная часть серии статей про трюки на си! В этой статье будет еще порция свежих хаков, фанов, трюков, еще больше магии и скорости!
Буду рад плюсам статье на Хабре

В конце декабря или начале января выйдет скорее всего заключительная 6 часть серии статей.

Сейчас пишу статью про полезные скрипты и алиасы на линукс, а также статью про устройство и написание ГПСЧ на C
15🔥1
Клон ChatGPT в 3000 байтах на C, основанный на GPT-2

Эта программа представляет собой свободную от зависимостей реализацию GPT-2. Она загружает матрицу весов и файл BPE из оригинальных файлов TensorFlow, токенизирует вывод при помощи простого энкодера, работающего по принципу частотного кодирования, реализует базовый пакет для линейной алгебры, в котором заключены математические операции над матрицами, определяет архитектуру трансформера, выполняет инференс трансформера, а затем очищает вывод от токенов при помощи BPE-декодера. Всё это — примерно в 3000 байт на C.

Код достаточно эффективно оптимизирован — настолько, что малый GPT-2 на любой современной машине выдаёт отклик всего за несколько секунд.
🔥2❤‍🔥1
Давайте проверим, знаете ли вы основные команды, практики, которые вокруг них существуют, и алгоритмы решения типовых ситуаций. Насколько уверенно вы можете ответить на следующие вопросы:

Почему стоит почти всегда начинать свою работу с команды git pull, если вы не forever alone на проекте?
Почему стоит пользоваться командой git push почаще (хотя бы раз в день)? Какие риски могут быть, если вы редко отправляете изменения в удалённый репозиторий?
Представьте, что вы сделали пуллреквест, отправили его на ревью. Ревьюер предложил вам мелкую правку прямо в ПР (например, поправил опечатку в слове) и вы нажали в интерфейсе Github кнопку "Commit changes". После нажатия на эту кнопку изменения попадут вам сразу и в локальный репозиторий?
Какие основные практики оформления коммитов вы знаете?
Зачем нужно ветвление в git?
Вы сделали коммит, отправили изменения в удалённый репозиторий. И тут в интерфейсе Github вдруг видите, что приехало не всё, над чем вы работали, точно должны были быть ещё какие-то файлы. Что пошло не так и как это исправить?
В вашей ветке есть конфликты с base branch. Как их разрешить?
Вы и коллега работали в разных ветках над разными фичами, но эти фичи могли затрагивать одни и те же файлы. Вы оба сделали ПР, но коллега замержил свой ПР быстрее, чем вы свой. В вашей ветке возникли конфликты. Вы их порешали, пересобрали свою ветку, чтобы проверить, что все ок, и при проверке понимаете, что что-то поломалось. Что-то отвалилось в том, над чем работали вы и/или пропали какие-то части изменений, которые вносил коллега.
Как всё исправить, чтобы в вашей ветке корректно работало то, над чем трудились вы, и были видны все изменения коллеги?
👍2❤‍🔥1
Понятия задачи (task), потока (thread) и процесса (process) в Linux

Task, thread и process – это, в принципе, достаточно близкие по смыслу понятия, но надо всё-таки разобраться, что каждое из них значит.

Когда вы запускаете приложение, в системе создаётся процесс (process), которому выделяется память на хранение исполняемого кода и других данных. В рамках этого процесса создаётся минимум один поток (thread). Именно среди потоков планировщики Linux и распределяют время процессора, а также решают, в какой очерёдности они будут выполняться. Задачей (task) можно назвать уже непосредственно сами инструкции, которые процессор получает и выполняет.

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

Running или Runnable (R) – процесс в состоянии running прямо сейчас использует процессорное время, в свою очередь runnable процесс только ожидает его.

Uninterruptible Sleep (D) – процесс ждёт результата операции ввода-вывода. Например, ждёт данные от диска. Такой процесс никак нельзя убить.

Interruptible Sleep (S) – процесс ждёт какое-то событие и не потребляет процессорного времени. Пример: ввод из командной строки.

Stopped (T) – процесс получил сигнал SIGSTOP или SIGTSTP и остановил свою работу. В этом состоянии процессу можно послать сигнал SIGCONT и запустить его снова.

Zombie (Z) – процесс, который получил сигналы на завершение работы, и полностью её завершил – он больше не потребляет ресурсов системы, только PID идентификатор. Он ждет, когда его родительский процесс выполнит системный вызов wait, после этого Zombie исчезнет. Иногда этого может не происходить, в таком случае приходится дебажить родителя.

Всю информации о процессе можно достать из папки /proc/<PID>, где <PID> – это идентификатор процесса. Если вам нужно получить информацию в более “user friendly” виде, то воспользуйтесь утилитами top, htop, ps и тд.
❤‍🔥2🔥1
Генератор случайных чисел Лемера

Очень быстрый генератор случайных чисел. Подробнее можно почитать здесь.

Алгоритм Lehmer64 — это быстрый генератор псевдослучайных чисел (ГПСЧ), основанный на мультипликативном линейном конгруэнтном методе. Он использует 128-битное состояние для генерации 64-битных случайных чисел, обеспечивая высокую производительность и достаточную статистическую случайность для большинства некриптографических задач.

> Мультипликативный линейный конгруэнтный метод (мультипликативный конгруэнтный метод) — это алгоритм для генерации псевдослучайных чисел, основанный на линейной рекуррентной формуле. Простыми словами, метод создаёт последовательность чисел, где каждое последующее число зависит от предыдущего, но при этом существует цикл, повторяющийся бесконечное число раз (период).

Принцип работы
Основная формула метода: Xn+1 = (a ⋅ Xn + c) mod m, где:

+ Xn+1 — следующее псевдослучайное число;
+ Xn — текущее псевдослучайное число;
+ a — мультипликативный множитель;
+ c — приращение;
+ m — модуль;
+ X0 — начальное значение (seed).

И вот его простейшая реализация на C:

static __uint128_t g_lehmer64_state;

uint64_t lehmer64(void) {
g_lehmer64_state *= 0xda942042e4dd58b5ULL;
return g_lehmer64_state >> 64;
}


Каждый раз, когда нужно новое число, мы умножаем состояние на константу 0xda942042e4dd58b5ULL (высчитанная экспериментальным путем). g_lehmer64_state - это состояние размером 128 бит, на старте в котором хранится нечетный сид. После этого берем старшие 64 бита и возвращаем их, младшие остаются.
❤‍🔥21
Forwarded from Хабр
Магия C: нестандартные трюки и быстрые алгоритмы

Промышленный код требует соблюдения стандартов, но иногда полезно заглянуть на территорию «ненормального программирования». В языке C всё ещё остаются лазейки для необычных оптимизаций и странных хаков, которые выглядят как магия, но работают прямо на уровне железа.

В основе подборки лежат математические алгоритмы и ГПСЧ. Каждое решение подкреплено графиками и бенчмарками, чтобы наглядно показать реальный прирост скорости.

Взглянем на скрытые возможности языка и разберём работу магических констант.
🔥31❤‍🔥11