Люди думают, что C это строгий язык
А C позволяет между делом вплести
Не показывайте это питонистам, они расплачутся.🥱
👉 @Cpportal
А C позволяет между делом вплести
switch внутрь while, поломать пространство-время, и оно спокойно скомпилится.Не показывайте это питонистам, они расплачутся.
#include <stdio.h>
int main() {
int i = 0;
switch (i) {
case 0:
while (i < 3) {
printf("%d", i);
case 1:
i++;
}
}
return 0;
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔28👍9❤5🤣3🔥1
setgid - системный вызов Linux #106
Идентичность процесса в Linux это иллюзия.
Ядро видит потоки.
POSIX ожидает процессы.
Возьмем
Он выставляет effective group ID (эффективный GID) у вызывающего процесса. Если вызывающий привилегирован (имеет capability
Если определить "процесс" как группу потоков, которые шарят память, ядро не обязано заставлять их шарить credentials. Если обойти стандартную библиотеку и дернуть сырой syscall в многопоточном приложении, изменится только вызывающий поток. В итоге получишь процесс с раздвоенной идентичностью: один поток уже ограничен, а фоновые worker-потоки продолжают работать со старыми групповыми привилегиями.
Чтобы это исправить, реализация потоков glibc NPTL делает синхронизационный танец. Когда ты вызываешь
Ниже C-программа, которая демонстрирует вызов raw syscall.
Это идеальный пример того, как механизм в ядре ОС отличается от спецификации POSIX , и какой “клей” нужен, чтобы все это склеить.
👉 @Cpportal
Идентичность процесса в Linux это иллюзия.
Ядро видит потоки.
POSIX ожидает процессы.
Возьмем
setgid (syscall #106 на x86_64).Он выставляет effective group ID (эффективный GID) у вызывающего процесса. Если вызывающий привилегирован (имеет capability
CAP_SETGID), он также выставляет real GID (реальный GID) и saved set-group-ID (сохраненный setgid). Чаще всего это видно, когда сервер вроде Nginx сбрасывает привилегии с root на менее привилегированную группу ради безопасности. Обычно ты предполагаешь, что это относится ко всему процессу. Но вот подвох: в Linux ядро ведет учет credentials (учетных данных) на уровне потока.Если определить "процесс" как группу потоков, которые шарят память, ядро не обязано заставлять их шарить credentials. Если обойти стандартную библиотеку и дернуть сырой syscall в многопоточном приложении, изменится только вызывающий поток. В итоге получишь процесс с раздвоенной идентичностью: один поток уже ограничен, а фоновые worker-потоки продолжают работать со старыми групповыми привилегиями.
Чтобы это исправить, реализация потоков glibc NPTL делает синхронизационный танец. Когда ты вызываешь
setgid(), обертка не просто вызывает сырой syscall. Она шлет сигнал каждому другому потоку в процессе. Обработчик сигнала в каждом потоке затем вызывает тот же syscall для самого себя, обновляя свои credentials, чтобы они совпали. glibc ждет, пока все потоки закончат обновление, и только потом возвращает управление. Так она выполняет семантику POSIX, где требуется, чтобы все потоки в процессе имели одинаковые credentials.Ниже C-программа, которая демонстрирует вызов raw syscall.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <errno.h>
int main() {
// We will try to switch to GID 1000
gid_t target_gid = 1000;
printf("Current GID: %d\n", getgid());
// We use the raw syscall (setgid)
// On a multi-threaded app, this is dangerous!
// It only updates the credential for the CURRENT thread.
printf("Calling raw setgid syscall...\n");
long ret = syscall(SYS_setgid, target_gid);
if (ret == 0) {
printf("Success! New GID: %d\n", getgid());
} else {
perror("Syscall failed (are you root?)");
}
return 0;
}
Это идеальный пример того, как механизм в ядре ОС отличается от спецификации POSIX , и какой “клей” нужен, чтобы все это склеить.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10
Сеньор: нам нужен service layer, repository layer и controller
C-разраб: у нас есть это
👉 @Cpportal
C-разраб: у нас есть это
#include <stdio.h>
int get_status(void) {
return 200; // репозиторий, видимо
}
void handle_request(void) {
printf("%d OK\n", get_status()); // сервис + контроллер
}
int main(void) {
handle_request();
return 0;
}
Please open Telegram to view this post
VIEW IN TELEGRAM
😁25❤6👎2
Да, в C есть указатели на массивы, размер которых известен только во время выполнения.
👉 @Cpportal
#include <stdio.h>
int main(void) {
int n = 5;
int (*arr)[n] = &(int[]){1, 2, 3, 4, 5};
for (int i = 0; i < n; i++)
printf("%d\n", (*arr)[i]);
return 0;
}
Please open Telegram to view this post
VIEW IN TELEGRAM
❤20🔥4💊4
Если ты платишь за девтулы, сохрани это: http://github.com/ripienaar/free-for-dev
Один из самых больших каталогов бесплатных тарифов в интернете.
- 85K+ звезд на GitHub
- покрывает облака, базы данных, CI/CD, API и хостинг
- комьюнити-кураторский список 100% бесплатных тиров
- экономит тебе тысячи долларов на сайд-проектах
- постоянно обновляется сообществом
Лучший читлист для бутстрапа🐐
👉 @Cpportal
Один из самых больших каталогов бесплатных тарифов в интернете.
- 85K+ звезд на GitHub
- покрывает облака, базы данных, CI/CD, API и хостинг
- комьюнити-кураторский список 100% бесплатных тиров
- экономит тебе тысячи долларов на сайд-проектах
- постоянно обновляется сообществом
Лучший читлист для бутстрапа
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - ripienaar/free-for-dev: A list of SaaS, PaaS and IaaS offerings that have free tiers of interest to devops and infradev
A list of SaaS, PaaS and IaaS offerings that have free tiers of interest to devops and infradev - ripienaar/free-for-dev
❤9👍2🔥2😁1
Появился новый порт быстрого float-парсера на чистом C.
Речь про библиотеку для парсинга чисел с плавающей точкой в стиле std::from_chars: из строки вроде "3.1416" сразу в double. В реальных задачах (например, при разборе JSON с кучей чисел, типа geojson) именно это часто становится главным триггером, поэтому быстрый парсер реально влияет на общую скорость.
Ранее были реализации/порты на C++, Java, C#, Rust, но прямого “чистого C” варианта не хватало. Для проектов вроде Redis это особенно важно: не хочется тащить C++ компилятор только ради парсинга.
Теперь есть аккуратный ручной порт от Koleman Nix: он проходит жёсткие тесты и при этом очень быстрый. Официального релиза пока нет, но код уже можно посмотреть:
https://github.com/kolemannix/ffc.h
По бенчмаркам местами получается топ по скорости: до 100 млн float в секунду (примерно 2 GB/s).
👉 @Cpportal
Речь про библиотеку для парсинга чисел с плавающей точкой в стиле std::from_chars: из строки вроде "3.1416" сразу в double. В реальных задачах (например, при разборе JSON с кучей чисел, типа geojson) именно это часто становится главным триггером, поэтому быстрый парсер реально влияет на общую скорость.
Ранее были реализации/порты на C++, Java, C#, Rust, но прямого “чистого C” варианта не хватало. Для проектов вроде Redis это особенно важно: не хочется тащить C++ компилятор только ради парсинга.
Теперь есть аккуратный ручной порт от Koleman Nix: он проходит жёсткие тесты и при этом очень быстрый. Официального релиза пока нет, но код уже можно посмотреть:
https://github.com/kolemannix/ffc.h
По бенчмаркам местами получается топ по скорости: до 100 млн float в секунду (примерно 2 GB/s).
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍5
Почему массивы в C начинаются с нуля
Я пишу
Вот что обычно никто не говорит:
компилятор на самом деле делает:
Квадратные скобки просто наряжают математику.
Но представь на секунду, что C использовал бы индексацию с 1, как какой-нибудь цивилизованный язык. Ты бы писал
Каждый. Отдельный. Доступ. Этот
Так что они выбрали ноль, потому что экономия одного CPU-цикла в 1972 году стоила того, чтобы путать новичков следующие 50 лет.
Я все время думаю про это вычитание. Это
Одна лишняя инструкция, возможно несколько тактов. Не элегантно. Просто экономно. И теперь мы застряли с этим. Каждый раз, когда кто-то постит мем из серии почему программирование такое сложное про нулевую индексацию, это эхо того, как Деннис Ритчи пытался сбрить микросекунду с текстового парсера в Нью-Джерси полвека назад.
И начинаешь думать, что еще мы делаем неправильно, потому что когда-то это было правильно. Какие еще острые углы - просто окаменевшие оптимизации? Может, большая часть того, что мы называем философией программирования, это просто то, что быстрее всего компилилось на железе, которое сейчас уже металлолом на свалке.🤢
В общем, я все равно буду писать
👉 @Cpportal
Я пишу
for(i=0; i<n; i++) с 11 лет, и ни разу не остановился, чтобы спросить: а почему вообще так. Это просто мышечная память, ритуальное заклинание, которое набираешь не глядя. Но на прошлой неделе кто-то спросил меня, почему массивы начинаются с нуля, и я открыл рот, чтобы объяснить, и вдруг понял, что вообще не знаю. Ноль неестественен. Никто не считает яблоки начиная с нулевого яблока. Это компьютерная штука, сказал я, туманно помахав в сторону адресов памяти. Но это звучало как отмазка, так что я полез копать, и, честно, стало понятнее, когда я посмотрел на PDP-11.Вот что обычно никто не говорит:
arr[i] - это ложь. Это синтаксический сахар. Под капотом там просто арифметика указателей. Когда ты пишешь так:int arr[5] = {10, 20, 30, 40, 50};
int x = arr[2];компилятор на самом деле делает:
int x = *(arr + 2);
Квадратные скобки просто наряжают математику.
arr - это указатель на базовый адрес, а 2 - это смещение. Если arr живет по адресу 1000, а int занимает 4 байта, ты берешь то, что лежит по адресу 1008. Ноль начинает выглядеть логично, потому что первый элемент находится по базовому адресу, то есть со смещением ноль.Но представь на секунду, что C использовал бы индексацию с 1, как какой-нибудь цивилизованный язык. Ты бы писал
arr[i], и под капотом компилятору нужно было бы делать:*(arr + i - 1)
Каждый. Отдельный. Доступ. Этот
- 1 - это лишняя инструкция вычитания. На PDP-11, этой красивой, тесной маленькой машинке, на которой родился C, циклы CPU были на вес золота. Ты чувствовал каждую инструкцию. Одно лишнее вычитание на каждый доступ к массиву, умноженное на каждый цикл, каждую строковую операцию, каждую заливку буфера - это реальные деньги.Так что они выбрали ноль, потому что экономия одного CPU-цикла в 1972 году стоила того, чтобы путать новичков следующие 50 лет.
Я все время думаю про это вычитание. Это
i - 1 компилилось бы во что-то вроде:MOV i, R0
SUB #1, R0 ; вот оно. вот этот налог.
MOV (arr,R0), x
Одна лишняя инструкция, возможно несколько тактов. Не элегантно. Просто экономно. И теперь мы застряли с этим. Каждый раз, когда кто-то постит мем из серии почему программирование такое сложное про нулевую индексацию, это эхо того, как Деннис Ритчи пытался сбрить микросекунду с текстового парсера в Нью-Джерси полвека назад.
И начинаешь думать, что еще мы делаем неправильно, потому что когда-то это было правильно. Какие еще острые углы - просто окаменевшие оптимизации? Может, большая часть того, что мы называем философией программирования, это просто то, что быстрее всего компилилось на железе, которое сейчас уже металлолом на свалке.
В общем, я все равно буду писать
for(i = 0; i < n; i ++). Но теперь я знаю, что считаю с нуля не потому что это логично. Я считаю с нуля потому, что вычитать единицу когда-то было слишком дорого.Please open Telegram to view this post
VIEW IN TELEGRAM
❤34🔥7
[Нужен Godbolt]. Да, для сложных типов это иногда верно, но для сценариев, прозрачных для оптимизатора, слово «всегда» здесь просто не подходит.
👉 @Cpportal
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11
Браузеры на Chromium открывают JSON-RPC интерфейс через Chrome DevTools Protocol. Это программный доступ к инструментированию, удалённой инспекции, отладке и автоматизации.
Браузер тут по сути превращается в playground для API, попробуй сам.
http://chromedevtools.github.io/devtools-protocol/
👉 @Cpportal
Браузер тут по сути превращается в playground для API, попробуй сам.
http://chromedevtools.github.io/devtools-protocol/
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7
Очень часто мне нужно временно отключить какой-то кусок кода. Я его закомменчиваю, но потом сталкиваюсь с проблемой: раз этот код вообще не компилируется, со временем он «протухает». Какие-то функции, которые он использует, могли измениться, а сам код при этом даже не проходит проверку типов. В итоге, когда я снова его включаю, он уже не компилируется, и мне приходится тратить кучу времени на починку.
Решение, до которого я пока дошёл, это «закомментировать» код через runtime
👉 @Cpportal
Решение, до которого я пока дошёл, это «закомментировать» код через runtime
if (0). Такой код никогда не выполнится, оптимизатор, скорее всего, вообще его полностью выкинет, но перед этим компилятор всё равно проверит его типы и сразу заставит меня исправить проблемы на месте.Please open Telegram to view this post
VIEW IN TELEGRAM
👍30❤4🤔2
Твой CPU спекулятивно выполнит ветку, которая вообще не должна была выполниться, подтянет секретные данные в кэш, а потом сделает вид, что ничего не произошло.
По сути,
👉 @Cpportal
По сути,
Spectre это: а что, если просто измерить по времени последствия этой лжи?Please open Telegram to view this post
VIEW IN TELEGRAM
❤9🤔2
Люди из мира OOP: «мы используем DI-фреймворк»
Люди из мира C: «мы передаём struct»
> и то и другое это dependency injection
👉 @Cpportal
Люди из мира C: «мы передаём struct»
> и то и другое это dependency injection
#include <stdio.h>
struct services {
void (*log)(const char *);
};
static void stderr_log(const char *msg) {
fprintf(stderr, "%s\n", msg);
}
int main(void) {
struct services s = { .log = stderr_log };
s.log("hello from my DI container");
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤5💊1
🔥 Подписка на easyoffer PRO на 1 год со скидкой 70%
easyoffer – сайт для подготовки к собеседованию на программиста, тестировщика и другие IT-профессии становится еще доступнее со скидкой 70% до 10 марта.
⚙️ Актуальные функции:
1. База вопросов из реальных технических собеседований с вероятностью встречи и примерами ответов.
2. База задач с этапа live-coding.
3. База видеозаписей 1100+ реальных собеседований, в том числе в топовые компании (Сбер, Авито, Яндекс, WB, OZON, МТС и др.) на позиции Junior/Middle/Senior.
4. База 400+ тестовых заданий от компаний.
5. Аналитика ТОП-требований из вакансий для лучшего написания резюме по ключевым словам.
6. Тренажеры для подготовки к собеседованию. В том числе тренажер «Реальное собеседование» со сценарием вопросов под конкретную компанию.
Акция до 10 марта (включительно) на PRO-тариф.
– Подписка действует 1 год
– Доступ ко всем профессиями сразу
👉 Смотри подробности тарифа и покупай на easyoffer
easyoffer – сайт для подготовки к собеседованию на программиста, тестировщика и другие IT-профессии становится еще доступнее со скидкой 70% до 10 марта.
⚙️ Актуальные функции:
1. База вопросов из реальных технических собеседований с вероятностью встречи и примерами ответов.
2. База задач с этапа live-coding.
3. База видеозаписей 1100+ реальных собеседований, в том числе в топовые компании (Сбер, Авито, Яндекс, WB, OZON, МТС и др.) на позиции Junior/Middle/Senior.
4. База 400+ тестовых заданий от компаний.
5. Аналитика ТОП-требований из вакансий для лучшего написания резюме по ключевым словам.
6. Тренажеры для подготовки к собеседованию. В том числе тренажер «Реальное собеседование» со сценарием вопросов под конкретную компанию.
Акция до 10 марта (включительно) на PRO-тариф.
– Подписка действует 1 год
– Доступ ко всем профессиями сразу
👉 Смотри подробности тарифа и покупай на easyoffer
💊1