C — язык, который славится своей простотой, скоростью и, конечно же, возможностью стрелять себе в ногу. Когда речь заходит о парсинге JSON, обычно представляются удобные библиотеки на Python или JavaScript. Но что, если совместить структурированность JSON с суровой прямотой языка C? Именно этим и занялся разработчик xnacly, создав удивительно дерзкий и творческий проект — JSON-парсер, реализованный на C с использованием методов структур.
📌 Почему это интересно?
Автор проекта решил не просто написать очередной парсер JSON, а пойти нестандартным путём:
- 🎯 Создать API, напоминающий методы структур из Go или Rust, используя указатели на функции в C.
- 🛠️ Обеспечить полную безопасность (без ошибок сегментации, утечек памяти и переполнений стека).
- 🧹 Предоставить удобный, эргономичный интерфейс для разработчиков.
Это амбициозная задача, ведь C по своей природе не предназначен для объектно-ориентированного подхода.
🎩 Как «оживить» структуры в C?
В C структуры не имеют методов в привычном смысле, но их можно имитировать через указатели на функции. Автор применил такой подход:
struct json {
char *input;
size_t pos;
size_t length;
// 🔧 Методы структуры через указатели на функции:
char (*cur)(struct json *);
bool (*is_eof)(struct json *);
void (*advance)(struct json *);
struct json_value (*parse)(struct json *);
};
Затем при инициализации структуры он явно назначает функции указателям, что и создаёт впечатление методов:
struct json json_new(char *input) {
struct json j = { .input = input, .length = strlen(input) - 1 };
j.cur = cur;
j.is_eof = is_eof;
j.advance = advance;
j.parse = parse;
return j;
}
Такой подход сильно напоминает Go или Rust, но реализован в старом-добром C.
⚡️ Интересные особенности реализации
В проекте использованы несколько необычных техник:
- 🎲 Вариативные макросы
Для упрощения написания JSON автор создал удобный макрос, позволяющий вставлять JSON прямо в код:
#define JSON(...) #__VA_ARGS__
// Использование:
char *raw_json = JSON({ "array": [1, 2, 3] });
Это существенно упрощает тестирование и примеры кода.
- 📦 Union-ы для экономии памяти
JSON-значения представлены через структуры и union-ы, чтобы эффективно использовать память для разных типов данных (числа, строки, булевы значения):
struct json_value {
enum json_type type;
union {
bool boolean;
char *string;
double number;
} value;
struct json_value *values;
char **object_keys;
size_t length;
}; - 🔍 Обработка памяти и утечек
Автор тщательно следит за утечками памяти и создал функцию для освобождения всех выделенных ресурсов:
void json_free_value(struct json_value *json_value) { ... }
🧪 Компиляция и флаги безопасности
Для безопасности и стабильности автор использует строгие флаги компилятора GCC:
- 🔒 -Wall, -Wextra, -Werror – максимально строгие проверки.
- 🚦 -fsanitize=address,undefined – инструменты для выявления ошибок памяти и неопределённого поведения.
- 🚨 -Wshadow, -Wstrict-prototypes, -Wcast-align – дополнительные проверки для чистоты и надёжности кода.
В итоге компиляция выглядит так:
gcc -std=c23 -O2 -Wall -Wextra -Werror -fsanitize=address,undefined main.c
🔥 Реализация парсера JSON
Парсер написан с нуля без использования сторонних библиотек. Он читает строку посимвольно, игнорируя пробелы и переводит символы в структурированные данные:
- 🎯 Парсинг атомарных значений (null, true, false, числа и строки).
- 📚 Парсинг массивов и объектов с динамическим выделением памяти и проверкой корректности структуры данных.
Особенно интересным моментом является использование assert-макроса для быстрого обнаружения ошибок во время парсинга:
#define ASSERT(EXP, context) \
if (!(EXP)) { \
fprintf(stderr, "Ошибка: " context "\n"); \
exit(EXIT_FAILURE); \
}
💡 Личное мнение автора статьи
Честно говоря, первоначально идея писать объектно-ориентированный код на C кажется слегка безумной. Но автор не просто «поигрался» с языком, а показал, как с помощью простых приёмов можно создать достаточно удобный и безопасный интерфейс.
Я считаю, что такой проект – это не просто забавный эксперимент, но и отличная демонстрация возможностей языка C, когда его используют творчески и осторожно. К тому же, подобные эксперименты могут вдохновить разработчиков на написание более безопасного и надёжного низкоуровневого кода.
🚧 Что можно улучшить?
- 🚀 Оптимизация памяти
Реализация постоянно использует realloc для каждого нового элемента массива или объекта. Можно улучшить, выделяя память с запасом. - 🔐 Поддержка полной спецификации JSON
Сейчас поддержка строк и чисел ограничена (нет экранированных символов, научной нотации). - 🧪 Полноценное тестирование и бенчмарки
Для надёжного использования в реальных проектах стоит добавить тесты и измерение производительности.
🎯 Кому и зачем это нужно?
Этот проект будет полезен:
- 🛠️ Тем, кто изучает C и хочет понять тонкости реализации структур и работы с памятью.
- 🔍 Разработчикам, ищущим вдохновение в реализации удобных API на низкоуровневых языках.
- 🎓 Студентам и преподавателям, которым нужен хороший учебный пример работы с JSON и указателями на функции.
✨ Итог: C — это мощно, весело и опасно. Но только если вы знаете, что делаете!
🔗 Ссылка:
🔥 Пробуйте, экспериментируйте и пишите красивый и безопасный код!