14864
Присоединяйтесь к нашему каналу и погрузитесь в мир для C/C++-разработчика Связь: @devmangx РКН: https://clck.ru/3Foc4d
Господи Иисусе, каждый раз, когда я вижу фрагмент продакшен-кода на C, я схожу с ума. Вы, люди, серьёзно так код пишете? 🤣🤣🤣
👉 @Cpportal
Назовите локальную переменную точно так же, как тип или макрос ключевого слова, и наблюдайте, как следующий разработчик, открывший этот файл, постепенно теряет связь с реальностью.
👉 @Cpportal
Многие реализации std::string в C++ хранят короткие строки непосредственно внутри самого объекта строки.
Выделение памяти в куче не требуется, пока длина строки не превысит размер доступного пространства.
Эта оптимизация называется SSO (Small String Optimization).
👉 @Cpportal
Аудиторы безопасности обнаружили в нашей кодовой базе на C потенциальные переполнения буфера.
Поэтому я заменил strcpy на реализацию с постоянным временем выполнения, которая не копирует ни одного байта пользовательских данных.
Нельзя повредить данные, которые ты даже не удосужился сохранить.
👉 @Cpportal
Классический алгоритм подсчёта установленных битов Брайана Кернигана на языке C сам по себе весьма изящен.
Но посмотрите, что делает Clang при компиляции с флагами -O2 -mpopcnt.
Компилятор распознаёт конструкцию n &= (n - 1), полностью устраняет цикл и заменяет его одной инструкцией POPCNT архитектуры x86.
👉 @Cpportal
Битовый трюк Госпера (Gosper’s hack) позволяет получить следующее целое число с точно таким же количеством установленных битов (единиц в двоичном представлении).
Впервые описанный в HAKMEM в 1970-х годах, этот алгоритм позволяет эффективно перебирать комбинации с помощью побитовых операций вместо рекурсии.
👉 @Cpportal
Исходный код самой первой версии Linux 0.01, выпущенной в 1991 году, представляет немалый интерес.
В Makefile Линус Торвальдс использовал инструменты для работы с 16-битным ассемблером наряду с компилятором GCC, чтобы собрать загрузочный образ ядра.
А теперь взгляните, как он обрабатывал критическую ошибку ядра (kernel panic):
👉 @Cpportal
🚀 29 октября Arenadata проведёт техническую онлайн-конференцию ArenaTech
На ArenaTech инженеры Arenadata расскажут, как устроены продукты компании изнутри, поделятся опытом решения сложных инженерных задач и представят ключевые направления технологического развития.
🟢Основные темы конференции:
🔜СУБД: архитектура, развитие и эксплуатация. Обсудим планы развития Arenadata DB (ADB) и Greengage DB, новые возможности MPP-СУБД, включая hot standby, вопросы безопасности и устранения уязвимостей. Отдельное внимание уделим утилите ggrebalance, которая позволяет сокращать число сегментов кластера и заменять хосты с сохранением равномерного распределения данных.
🔜Платформа данных: безопасность и Kubernetes. Расскажем об управлении секретами и доступом в Arenadata Hyperwave (ADH) с использованием OpenBao. Разберём особенности переноса Impala, Trino и Spark в Kubernetes: интеграцию с Kerberos, разработку операторов, адаптацию Spark и использование Celeborn и YuniKorn.
🔜Инструменты: кластерный менеджер, документация, ИИ-поиск. Поделимся опытом организации процессов разработки технической документации и расскажем, как создавались интеллектуальный поиск и ИИ-ассистент, упрощающие поиск информации в документации многокомпонентной платформы данных. Также расскажем про развитие нашего кластерного менеджера ADCM.
После каждого доклада участники смогут задать вопросы спикерам в рамках Q&A-сессии.
Конференция будет интересна разработчикам, дата-инженерам, администраторам СУБД, архитекторам, DevOps-инженерам и техническим руководителям.
🗓 29 октября, 12:00 МСК
Формат: онлайн 🔛
Программа и регистрация
В Unix V7 (1979 года) команда file могла определять, написан ли текст на английском языке, анализируя частоту встречаемости букв.
Она учитывала гласные, часто встречающиеся и редкие буквы.
Простая эвристика, которая в некоторой степени работает до сих пор.
👉 @Cpportal
Безопасная и простая реализация mkdir на C.
👉 @Cpportal
Оптимизация кода — невероятно увлекательная тема.
Когда вы умножаете число на константу (например, на 24), LLVM заменяет инструкцию умножения (imul) комбинацией побитового сдвига влево (shl) и вычисления эффективного адреса (lea).
Сдвиг влево на 3 бита эквивалентен умножению на 8, а инструкция lea выполняет арифметические операции над выражением вида [base + index] и сохраняет полученный результат.
И всё это буквально ради экономии одного такта процессора! Ведь imul выполняется за 3 такта, а shl и lea — за 1 такт каждая.
Для множества других констант существуют таблицы с аналогичными эвристиками оптимизации. Разработчики оптимизирующих бэкендов компиляторов прилагают огромные усилия, чтобы сэкономить даже одну инструкцию, поэтому не сводите всю их работу на нет!
👉 @Cpportal
В своей лекции по случаю вручения премии Тьюринга Кен Томпсон показал, как компилятор C может внедрить бэкдор в программу login и скрыть атаку даже от собственного исходного кода.
Сам компилятор становится бэкдором, не оставляя никаких следов в исходном коде.
👉 @Cpportal
Когда ядро Linux удаляет элемент из связного списка с помощью list_del(), оно не устанавливает указатели next и prev в NULL.
В типичных 64-битных системах вместо этого им присваиваются значения 0xdead000000000100 и 0xdead000000000122 (LIST_POISON1 и LIST_POISON2).
Эти заведомо некорректные адреса помогают обнаруживать ошибки, при которых код случайно обращается к удалённому элементу списка. Вместо того чтобы незаметно перейти по устаревшему указателю, ядро может вызвать исключение при обращении к легко распознаваемому адресу.
Этот механизм называется отравлением указателей (pointer poisoning).
👉 @Cpportal
Если заглянуть в исходный код ядра Linux, можно заметить, что проверки ошибок повсеместно обёрнуты в макросы likely() и unlikely().
Они используют __builtin_expect, чтобы подсказать компилятору переместить редко выполняемые инструкции обработки ошибок в конец функции. Благодаря этому кэш инструкций L1 процессора остаётся заполненным кодом наиболее часто выполняемого пути (fast path).
👉 @Cpportal
Интервьюер: Поменяйте местами два целых числа в C без использования третьей временной переменной и без риска арифметического переполнения.
Системный программист:
В Linux есть удивительно простой способ остановить программу на C, застрявшую в бесконечном цикле.
Достаточно вызвать alarm(3), и ядро запланирует отправку сигнала SIGALRM вашему процессу примерно через 3 секунды.
Если вы не изменяли стандартное поведение этого сигнала, процесс завершится.
Никакого цикла опроса и отдельного потока watchdog. Всего один вызов функции.
👉 @Cpportal
Когда Python-разработчик преобразует целое число в float, среда выполнения создаёт новый объект float.
Когда программист на C хочет интерпретировать те же самые 4 байта как float, он может просто скопировать биты, а всё остальное сделает IEEE 754.
👉 @Cpportal
Все жалуются, что Bogosort имеет сложность O(N!) и слишком медленный для использования в продакшене.
Поэтому я реализовал Quantum Bogosort на C.
Если массив ещё не отсортирован, программа просто уничтожает собственную вселенную.
Выживают только те временные линии, в которых массив уже был отсортирован.
👉 @Cpportal
Округление вверх до ближайшей степени двойки с помощью нескольких побитовых операций.
Классический битовый трюк, который десятилетиями используется в аллокаторах, хеш-таблицах и при управлении памятью.
👉 @Cpportal
В команде shutdown операционной системы FreeBSD есть функция с названием die_you_gravy_sucking_pig_dog().
Да, это настоящее имя функции.
Даже завершение работы системы заслуживает немного индивидуальности.
👉 @Cpportal
В 1996 году студия Naughty Dog выпустила Crash Bandicoot для оригинальной PlayStation, у которой было всего 2 МБ оперативной памяти.
Некоторые уровни занимали более 10 МБ, поэтому загрузить целый уровень в память одновременно было невозможно.
Тогда программист Энди Гэвин разработал собственную систему виртуальной памяти, которая подгружала с компакт-диска блоки данных размером 64 КБ по мере того, как Крэш перемещался по игровому миру.
Обычно игра загружала около трёх таких блоков в секунду. Данные на диске располагались в тщательно рассчитанном порядке, чтобы подгрузка не прерывала игровой процесс.
Представьте: целые трёхмерные миры загружались с компакт-диска со скоростью чтения около 300 КБ/с, а игра при этом должна была работать с частотой 30 кадров в секунду.
И всё это на консоли всего с 2 МБ оперативной памяти.
👉 @Cpportal
В 1998 году Брайан Керниган захотел создать движок регулярных выражений, настолько компактный, чтобы его исходный код целиком поместился на одной странице книги по программированию.
Роб Пайк отправился к себе в кабинет и спустя час или два вернулся с реализацией примерно на 30 строках кода на языке C.
Движок поддерживал метасимволы ^, $, . и *, а его реализация практически целиком основывалась на указателях и рекурсии.
Позднее Керниган включил этот код в книгу «Beautiful Code» («Совершенный код»).
👉 @Cpportal
В сентябре 1992 года разработчики Unix столкнулись с серьёзной проблемой при работе с Unicode. Хранение символов в 16-битном представлении могло приводить к появлению нулевых байтов, которые программы на C воспринимали как признак окончания строки. Более ранние кодировки также имели свои недостатки совместимости.
Однажды вечером Кен Томпсон и Роб Пайк отправились в небольшую закусочную в Нью-Джерси. Там Томпсон набросал схему новой кодировки прямо на бумажной подложке для тарелки.
Её устройство позволяло полностью сохранить совместимость с ASCII. Остальные символы представлялись последовательностями из нескольких байтов, причём такое представление исключало случайное появление нулевых байтов и разделителей путей Unix.
Вернувшись в Bell Labs, разработчики приступили к реализации своего замысла. Уже к пятнице их операционная система Plan 9 целиком работала с новой кодировкой.
Так появилась UTF-8.
Сегодня, спустя более тридцати лет, эта кодировка используется более чем на 99% веб-сайтов, для которых известно представление символов.
👉 @Cpportal
Оказывается, memcpy вполне неплохо подходит для сериализации.
Звучит очевидно, но я уже собирался писать для этого отдельную функцию, пока не заметил, что по сути просто изобретаю слегка приукрашенный memcpy.
👉 @Cpportal
До стандартизации операторов присваивания в языке C использовались операторы с обратным порядком символов, например =+ вместо +=.
Знаменитый фрагмент кода с комментарием «Вы не должны этого понимать» в те времена выглядел ещё более странно.
👉 @Cpportal
В оригинальном исходном коде Doom 1993 года кто-то оставил это в главном заголовочном файле.
У id Software явно было своё мнение о языках программирования.
👉 @Cpportal
Посмотрите, как раньше традиционно реализовывали макрос offsetof() в <stddef.h> на чистом C, ещё до появления встроенных функций компилятора.
Он приводит 0 (NULL) к указателю на структуру, получает адрес её поля через & и ->member, а затем преобразует полученный адрес в тип size_t.
Это не приводит к сбою, поскольку оператор & лишь вычисляет адрес на этапе компиляции, не обращаясь к памяти по нулевому адресу.
👉 @Cpportal
Удалёнка — топ для работодателя
Удалёнку почему-то до сих пор обсуждают так, будто это подарок сотруднику.
Якобы, работодатель разрешил работать из дома — радуйся.
Однако бизнесу удалёнка тоже очень выгодна
Аренда, ремонт, мебель, электричество, уборка, охрана, кофе, техника — офис стоит денег. И немаленьких.
Чем меньше людей нужно каждый день усаживать за столы, тем меньше компания тратит просто на то, чтобы эти столы существовали.
Не нужно искать человека среди тех, кто живёт рядом с офисом, готов ездить туда каждый день или вообще согласен переехать.
Можно нанять хорошего специалиста из Петербурга, Казани, Новосибирска, Калининграда — откуда угодно.
Допустим, у кандидата два похожих оффера.
В одном — три дня в неделю надо тащиться в офис. В другом — работаешь откуда удобно.
При прочих равных какой он выберет?
Вот и получается, что за сильных людей можно конкурировать не только деньгами.
В офисе очень легко подойти к человеку:
— Есть минутка?
И через 40 минут вы всё ещё треплетесь, а потом ещё вспоминай, что ты делал до этого.
На удалёнке между мыслью и человеком появляется фильтр: сначала сформулируй, потом напиши, потом дождись ответа, а лучше сделай сам.
Решето Эратосфена позволяет найти все простые числа до примерно 8 миллионов, используя всего 1 МБ памяти.
Каждое число представлено одним битом, а составные числа помечаются с помощью простых побитовых операций.
Этот метод до сих пор используется в генераторах простых чисел и при выборе оптимальных размеров хеш-таблиц.
👉 @Cpportal
В C, если вам нужен макрос, который при каждом развёртывании в пределах файла генерирует гарантированно уникальное имя переменной или структуры, в GCC и Clang есть малоизвестный встроенный макрос __COUNTER__.
Он автоматически увеличивает своё значение на единицу (0, 1, 2, 3...) каждый раз, когда препроцессор обрабатывает его.
👉 @Cpportal