Обычно думают что перегрузка функций это чисто фича C++, но в C11 есть _Generic, который позволяет делать диспетчинг по типу на этапе компиляции. Это стандартный C, без расширений и без рантайм-оверхеда.
👉 @Cpportal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥26❤7💊2
В C можно намеренно докладывать данные сразу после структуры. Один malloc, один сплошной блок в памяти. Полезно если понимаешь что делаешь, опасно если нет.
👉 @Cpportal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21❤5👎1🔥1👀1
Каждый раз когда вижу цикл ради вывода пробелов, вспоминаю что printf решил эту задачу ещё десятки лет назад.
Ширину можно передавать динамически. %*s в C делает больше работы чем многие думают.
👉 @Cpportal
Ширину можно передавать динамически. %*s в C делает больше работы чем многие думают.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20❤3😁3
Создание процесса в Linux устроено хитрее, чем кажется.
Можно подумать, что fork() тупо дублирует весь процесс: хип, стек и так далее. Наивно это выглядело бы как полный копипаст всей памяти.
Но копировать гигабайты RAM только чтобы запустить shell-команду? Система бы просто подвисала.
На деле используется Copy-on-Write (COW).
Таблицы страниц родителя и потомка указывают на одни и те же физические фреймы памяти.
В момент когда один из процессов пытается записать что-то в память, ядро ловит page fault, копирует только конкретную страницу на 4 КБ и продолжает выполнение.
fork() интересен ещё тем, что возвращается дважды.
Один раз в родителя (возвращает PID ребёнка), и один раз в ребёнка (возвращает 0).
Так вселенная раскалывается надвое, и один участок кода обслуживает два пути выполнения.
Под капотом, однако, glibc при вызове fork() даже не вызывает системный вызов fork!
Она вызывает clone — швейцарский нож, который лежит в основе создания тредов и других задач.
Системный вызов fork в ядре остался, но glibc трактует его как clone с настройками для классического дублирования процесса.
👉 @Cpportal
Можно подумать, что fork() тупо дублирует весь процесс: хип, стек и так далее. Наивно это выглядело бы как полный копипаст всей памяти.
Но копировать гигабайты RAM только чтобы запустить shell-команду? Система бы просто подвисала.
На деле используется Copy-on-Write (COW).
Таблицы страниц родителя и потомка указывают на одни и те же физические фреймы памяти.
В момент когда один из процессов пытается записать что-то в память, ядро ловит page fault, копирует только конкретную страницу на 4 КБ и продолжает выполнение.
fork() интересен ещё тем, что возвращается дважды.
Один раз в родителя (возвращает PID ребёнка), и один раз в ребёнка (возвращает 0).
Так вселенная раскалывается надвое, и один участок кода обслуживает два пути выполнения.
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
printf("I am the child!\n");
} else {
printf("I am the parent of %d\n", pid);
}
return 0;
}
Под капотом, однако, glibc при вызове fork() даже не вызывает системный вызов fork!
Она вызывает clone — швейцарский нож, который лежит в основе создания тредов и других задач.
Системный вызов fork в ядре остался, но glibc трактует его как clone с настройками для классического дублирования процесса.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍9
Context Pattern
FP, OOP, процедурщина и декларативщина объединены для создания единственного и последнего дизайн-паттерна, который вам когда-либо понадобится.
Одна структура (record), содержащая все зависимости, и которую вы явно передаете в каждую функцию.
Больше никакого наследования.
Больше никаких классов и методов.
Больше никакого dependency injection.
Больше никакого singleton.
Больше никаких private/public.
Моки проще некуда.
Это единственный паттерн, который нужен для структурирования ЛЮБОГО ПРИЛОЖЕНИЯ, В ЛЮБОЙ ИНДУСТРИИ (микросервис, компилятор, космическая система).
В Haskell это известно как «шаблон ручки» (The Handle Pattern)
👉 @Cpportal
FP, OOP, процедурщина и декларативщина объединены для создания единственного и последнего дизайн-паттерна, который вам когда-либо понадобится.
Одна структура (record), содержащая все зависимости, и которую вы явно передаете в каждую функцию.
Больше никакого наследования.
Больше никаких классов и методов.
Больше никакого dependency injection.
Больше никакого singleton.
Больше никаких private/public.
Моки проще некуда.
Это единственный паттерн, который нужен для структурирования ЛЮБОГО ПРИЛОЖЕНИЯ, В ЛЮБОЙ ИНДУСТРИИ (микросервис, компилятор, космическая система).
В Haskell это известно как «шаблон ручки» (The Handle Pattern)
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👎5🔥5🥱3👍1
Много C-программ до сих пор вручную пишут парсинг циклом под простые форматы. Хотя в стандартной библиотеке уже есть scanset'ы в scanf для парсинга по разделителям.
Если задать ширину полей и проверять код возврата, это полностью корректный ISO C. Без сторонних библиотек и без зависимости от компилятора.
Ручные циклы не делают код более низкоуровневым, они часто просто избыточны. scanf со scanset'ами уже дает ограниченное чтение, контроль по разделителям и предсказуемое поведение. Проверяешь код возврата, задаешь ширину полей и получаешь переносимый ISO C.
👉 @Cpportal
Если задать ширину полей и проверять код возврата, это полностью корректный ISO C. Без сторонних библиотек и без зависимости от компилятора.
Ручные циклы не делают код более низкоуровневым, они часто просто избыточны. scanf со scanset'ами уже дает ограниченное чтение, контроль по разделителям и предсказуемое поведение. Проверяешь код возврата, задаешь ширину полей и получаешь переносимый ISO C.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤17👍8😁1
Разработчик завершил реализацию собственного ECS-движка на C и заявил, что его система примерно в 17 раз быстрее Unity DOTS в веб-среде. В демонстрационном тесте симуляция 100 тысяч boids работала на ~90 FPS против ~17 FPS у Unity.
Автор пообещал позже выложить исходники и ссылку на демо. Тестовые параметры:
• Windows 10 64-bit
• Chrome с включённым force-high-performance-gpu
• CPU: AMD Ryzen 7 5800H (8C/16T)
• GPU: NVIDIA GeForce RTX 3060 Laptop
• RAM: 32 GB
В сцене рендерилось ~31 млн треугольников на кадр с PBR-освещением. Имплементация ECS была выполнена максимально близко к репозиторию Unity EntitiesSamples. В Unity были активированы и WebGPU, и wasm-threads, обе сборки — release с агрессивной оптимизацией.
Отмечается, что разница в FPS в демке составляет около 5x, поскольку упор идет в GPU. При этом сама ECS-симуляция на кастомном движке работает на ~430 FPS против ~22 FPS у Unity. Время измерялось одинаково в обоих случаях — по обновлению ECS World.
Разработчик отметил, что ECS-архитектура вдохновлена flecs, но был добавлен этап кодогенерации, позволяющий избавиться от хрупких участков кода и типичных ошибок.
👉 @Cpportal
Автор пообещал позже выложить исходники и ссылку на демо. Тестовые параметры:
• Windows 10 64-bit
• Chrome с включённым force-high-performance-gpu
• CPU: AMD Ryzen 7 5800H (8C/16T)
• GPU: NVIDIA GeForce RTX 3060 Laptop
• RAM: 32 GB
В сцене рендерилось ~31 млн треугольников на кадр с PBR-освещением. Имплементация ECS была выполнена максимально близко к репозиторию Unity EntitiesSamples. В Unity были активированы и WebGPU, и wasm-threads, обе сборки — release с агрессивной оптимизацией.
Отмечается, что разница в FPS в демке составляет около 5x, поскольку упор идет в GPU. При этом сама ECS-симуляция на кастомном движке работает на ~430 FPS против ~22 FPS у Unity. Время измерялось одинаково в обоих случаях — по обновлению ECS World.
Разработчик отметил, что ECS-архитектура вдохновлена flecs, но был добавлен этап кодогенерации, позволяющий избавиться от хрупких участков кода и типичных ошибок.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤27👍7🔥3
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔5❤3👍1
Не сливаем байты на булевы флаги.
В C есть очень аккуратный способ упаковать их впритык через битовые поля — это идеально для флагов, статусных регистров, протокольных хедеров и вообще любых штук, где важен каждый бит.
Вместо 4 отдельных int ты можешь впихнуть 32 флага всего в 4 байта.
Только не забывай: выравнивание и раскладка зависят от реализации, так что проверяй на целевой платформе.
👉 @Cpportal
В C есть очень аккуратный способ упаковать их впритык через битовые поля — это идеально для флагов, статусных регистров, протокольных хедеров и вообще любых штук, где важен каждый бит.
Вместо 4 отдельных int ты можешь впихнуть 32 флага всего в 4 байта.
Только не забывай: выравнивание и раскладка зависят от реализации, так что проверяй на целевой платформе.
#include <stdio.h>
struct user_flags {
unsigned int is_active : 1; // по одному биту на поле
unsigned int is_admin : 1;
unsigned int is_banned : 1;
unsigned int email_verified : 1;
unsigned int has_two_factor : 1;
unsigned int is_premium : 1;
unsigned int can_post : 1;
unsigned int can_comment : 1;
unsigned int reserved : 24; // пока не используется
};
int main() {
struct user_flags current_user = {0};
current_user.is_active = 1;
current_user.is_admin = 1;
current_user.email_verified = 1;
current_user.is_premium = 1;
printf("этой структуре нужно всего %zu байт (влезает в 4!)\n", sizeof(current_user));
if (current_user.is_admin && current_user.is_premium) {
printf("у пользователя есть admin и premium доступ\n");
}
// перевернуть статус banned
current_user.is_banned = !current_user.is_banned;
return 0;
}
Please open Telegram to view this post
VIEW IN TELEGRAM
❤18👍4🔥3
Please open Telegram to view this post
VIEW IN TELEGRAM
❤27😁9🔥2
Это единственный верный путь держать enum и строки в C в идеальном sync.
Один источник правды, без ручных маппингов и без расхождений.
X-Macros генерирует как перечисления, так и строки из одного и того же списка.
Чистый стандартный C. Используется там, где действительно важна корректность.
👉 @Cpportal
Один источник правды, без ручных маппингов и без расхождений.
X-Macros генерирует как перечисления, так и строки из одного и того же списка.
Чистый стандартный C. Используется там, где действительно важна корректность.
#include <stdio.h>
#define COLOR_TABLE \
X(RED, "Красный цвет") \
X(GREEN, "Зеленый цвет") \
X(BLUE, "Синий цвет") \
X(UNKNOWN, "Неизвестная сущность")
typedef enum {
#define X(name, str) COLOR_##name,
COLOR_TABLE
#undef X
} Color;
const char* ColorStrings[] = {
#define X(name, str) str,
COLOR_TABLE
#undef X
};
int main(void) {
Color c = COLOR_GREEN;
printf("Enum ID: %d соответствует строке: %s\n", c, ColorStrings[c]);
return 0;
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥18👍7❤5🤔1🌚1
const в C это не про оптимизацию.
Он задает, что функция имеет право делать.
Нарушишь контракт и компилятор тебя остановит.
Это сильнее, чем комментарий.
👉 @Cpportal
Он задает, что функция имеет право делать.
Нарушишь контракт и компилятор тебя остановит.
Это сильнее, чем комментарий.
#include <stddef.h>
size_t checksum(const unsigned char *data, size_t len)
{
size_t sum = 0;
for (size_t i = 0; i < len; ++i)
sum += data[i];
return sum;
}
Please open Telegram to view this post
VIEW IN TELEGRAM
❤23
Zen C теперь публично доступен!
С этим новым языком можно писать в стиле высокоуровневых языков, но при этом иметь доступ ко всей экосистеме C и не терять в производительности.
Можно поиграться с плагинами и даже написать свои. Потому что Zen C — это не только язык, но и полноценный набор инструментов.
Производственная готовность у проекта пока отсутствует, баги есть и их просят репортить. Тем не менее вся исходная база уже открыта, тесты и документация в работе, а функциональность доступна
👉 @Cpportal
С этим новым языком можно писать в стиле высокоуровневых языков, но при этом иметь доступ ко всей экосистеме C и не терять в производительности.
Можно поиграться с плагинами и даже написать свои. Потому что Zen C — это не только язык, но и полноценный набор инструментов.
Производственная готовность у проекта пока отсутствует, баги есть и их просят репортить. Тем не менее вся исходная база уже открыта, тесты и документация в работе, а функциональность доступна
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - z-libs/Zen-C: Write like a high-level language, run like C.
Write like a high-level language, run like C. Contribute to z-libs/Zen-C development by creating an account on GitHub.
❤13👍7😁5🥱3🤣2
This media is not supported in your browser
VIEW IN TELEGRAM
Преобразование бинарного числа в десятичное на C.
Есть несколько способов сделать это. Вот один из примеров.
👉 @Cpportal
Есть несколько способов сделать это. Вот один из примеров.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤19💊3👍1👎1😁1
Если твоему C-коду нужно 5 временных структур, тебе не нужен более безопасный язык, тебе нужно научиться писать на C.
Многие называют C небезопасным и грязным, игнорируя compound literals и designated initializers.
Собирай структуры прямо в месте вызова: без временных переменных, без багов из-за порядка и без лишних накладных расходов.
👉 @Cpportal
Многие называют C небезопасным и грязным, игнорируя compound literals и designated initializers.
Собирай структуры прямо в месте вызова: без временных переменных, без багов из-за порядка и без лишних накладных расходов.
sendmsg(sock,
&(struct msghdr){
.msg_name = &(struct sockaddr_in){
.sin_family = AF_INET,
.sin_port = htons(9000),
.sin_addr = { .s_addr = INADDR_ANY }
},
.msg_namelen = sizeof(struct sockaddr_in),
.msg_iov = iov,
.msg_iovlen = 1,
},
0
);
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10🔥9🤔7👍5😁2
Media is too big
VIEW IN TELEGRAM
В отличие от Windows, в Linux нет встроенного message box, который можно показать обычному пользователю, чтобы ему не пришлось заново запускать программу из терминала или лезть в логи.
Так что давайте сделаем свой с нуля на C, без GUI-тулкитов!👏
Версия с чуть выше битрейтом
GitHub со всеми исходниками
👉 @Cpportal
Так что давайте сделаем свой с нуля на C, без GUI-тулкитов!
Версия с чуть выше битрейтом
GitHub со всеми исходниками
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3🔥3