У меня появилась необходимость общаться с сервером через JSON-сообщения. Генерировать я их научился очевидным образом — ручной сборкой сообщения через sprintf. Однако мне нужно было ещё и разбирать ответ сервера, и чтобы не городить самописный парсер, попробовал найти готовые решения.

Благо, тут целых 17 готовых парсеров JSON в C. Некоторые (такие как YAJL) не захотели собираться с пол-пинка, да и странно выглядит когда решение такой довольно простой задачи разбивают на 10 модулей. Поэтому был выбран парсер cJSON, который умещается в два файла.

Использование cJSON

Использовать его крайне просто. Подключаем .h в инклуды, .c в дерево проекта, создаём строку JSON, например: char text1[]=»{«type»: 1, «value»: {«counters»: «abc»}}»; Для парсинга — вызываем метод JSON_Parse (он создаёт дерево сообщения), и складываем его вывод в переменную типа cJSON.

Теперь по дереву можно легко передвигаться методом cJSON_GetObjectItem. Этот метод возвращает новый объект cJSON, то есть для того чтобы добраться до листа — нужно вложить несколько cJSON_GetObjectItem друг в друга.

Получив, наконец, искомый лист (имеющий тип cJSON) — переводим его в строку методом cJSON_Print. Он возвращает char*, то есть его можно выводить в sprintf и подобных функциях (советую почитать исходный код — он простой, и может прояснить некоторые вопросы). Единственная проблема, которая на самом деле не является проблемой — все значения возвращаются в виде строк, но эти строки легко преобразовать в нужные числа, boolean и так далее.

Код

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "cJSON.h"

int state=0;

void json_work(char *text)
{
	cJSON *json=cJSON_Parse(text);
  char *out=cJSON_Print(cJSON_GetObjectItem(cJSON_GetObjectItem(json, "value"), "counters"));
  //Теперь имеем строку out
  cJSON_Delete(json);
  free(out);
}

void initGPIO()
{
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_Init(GPIOC, &GPIO_InitStructure);  
  GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_RESET);
}

int i=0;

int main(void)
{
  char json[]="{"type": 1, "value": {"counters": 150}}";	

  initGPIO();

  while(1)
  {
    for(i=0; i<1000; i++)
      json_work(json); //0.3 мс на весь разбор
    GPIOC->ODR ^= GPIO_Pin_8;
    state=1-state;
  }
}

Код никак не использует вытащенное значение, но тем не менее успешно делает это 1000 раз для определения времени работы. На плате STM32-VLDiscovery с процессором STM32F100 у меня получилось около 0.3мс на один цикл разбора.