Json in C

Here’s the translation of the JSON example from Go to C:

Our program will demonstrate JSON encoding and decoding in C. We’ll use the cJSON library for JSON operations.

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

// Define structs for our custom types
typedef struct {
    int page;
    char** fruits;
    int fruits_count;
} Response1;

typedef struct {
    int page;
    char** fruits;
    int fruits_count;
} Response2;

int main() {
    // Encoding basic data types to JSON strings
    cJSON *json_bool = cJSON_CreateBool(1);
    char *json_bool_str = cJSON_Print(json_bool);
    printf("%s\n", json_bool_str);
    free(json_bool_str);
    cJSON_Delete(json_bool);

    cJSON *json_int = cJSON_CreateNumber(1);
    char *json_int_str = cJSON_Print(json_int);
    printf("%s\n", json_int_str);
    free(json_int_str);
    cJSON_Delete(json_int);

    cJSON *json_float = cJSON_CreateNumber(2.34);
    char *json_float_str = cJSON_Print(json_float);
    printf("%s\n", json_float_str);
    free(json_float_str);
    cJSON_Delete(json_float);

    cJSON *json_string = cJSON_CreateString("gopher");
    char *json_string_str = cJSON_Print(json_string);
    printf("%s\n", json_string_str);
    free(json_string_str);
    cJSON_Delete(json_string);

    // Encoding slices and maps
    cJSON *json_array = cJSON_CreateArray();
    cJSON_AddItemToArray(json_array, cJSON_CreateString("apple"));
    cJSON_AddItemToArray(json_array, cJSON_CreateString("peach"));
    cJSON_AddItemToArray(json_array, cJSON_CreateString("pear"));
    char *json_array_str = cJSON_Print(json_array);
    printf("%s\n", json_array_str);
    free(json_array_str);
    cJSON_Delete(json_array);

    cJSON *json_object = cJSON_CreateObject();
    cJSON_AddNumberToObject(json_object, "apple", 5);
    cJSON_AddNumberToObject(json_object, "lettuce", 7);
    char *json_object_str = cJSON_Print(json_object);
    printf("%s\n", json_object_str);
    free(json_object_str);
    cJSON_Delete(json_object);

    // Encoding custom data types
    Response1 res1 = {1, (char*[]){"apple", "peach", "pear"}, 3};
    cJSON *json_res1 = cJSON_CreateObject();
    cJSON_AddNumberToObject(json_res1, "Page", res1.page);
    cJSON *fruits_array = cJSON_CreateStringArray((const char**)res1.fruits, res1.fruits_count);
    cJSON_AddItemToObject(json_res1, "Fruits", fruits_array);
    char *json_res1_str = cJSON_Print(json_res1);
    printf("%s\n", json_res1_str);
    free(json_res1_str);
    cJSON_Delete(json_res1);

    // Decoding JSON data
    const char *json_data = "{\"num\":6.13,\"strs\":[\"a\",\"b\"]}";
    cJSON *json = cJSON_Parse(json_data);
    if (json == NULL) {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL) {
            fprintf(stderr, "Error before: %s\n", error_ptr);
        }
        exit(1);
    }

    cJSON *num = cJSON_GetObjectItemCaseSensitive(json, "num");
    if (cJSON_IsNumber(num)) {
        printf("num: %f\n", num->valuedouble);
    }

    cJSON *strs = cJSON_GetObjectItemCaseSensitive(json, "strs");
    if (cJSON_IsArray(strs)) {
        cJSON *str = cJSON_GetArrayItem(strs, 0);
        if (cJSON_IsString(str) && (str->valuestring != NULL)) {
            printf("First string: %s\n", str->valuestring);
        }
    }

    cJSON_Delete(json);

    // Decoding JSON into custom data types
    const char *json_res2_str = "{\"page\": 1, \"fruits\": [\"apple\", \"peach\"]}";
    cJSON *json_res2 = cJSON_Parse(json_res2_str);
    if (json_res2 == NULL) {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL) {
            fprintf(stderr, "Error before: %s\n", error_ptr);
        }
        exit(1);
    }

    Response2 res2;
    cJSON *page = cJSON_GetObjectItemCaseSensitive(json_res2, "page");
    if (cJSON_IsNumber(page)) {
        res2.page = page->valueint;
    }

    cJSON *fruits = cJSON_GetObjectItemCaseSensitive(json_res2, "fruits");
    if (cJSON_IsArray(fruits)) {
        res2.fruits_count = cJSON_GetArraySize(fruits);
        res2.fruits = malloc(res2.fruits_count * sizeof(char*));
        for (int i = 0; i < res2.fruits_count; i++) {
            cJSON *fruit = cJSON_GetArrayItem(fruits, i);
            if (cJSON_IsString(fruit) && (fruit->valuestring != NULL)) {
                res2.fruits[i] = strdup(fruit->valuestring);
            }
        }
    }

    printf("Page: %d\n", res2.page);
    printf("First fruit: %s\n", res2.fruits[0]);

    // Clean up
    for (int i = 0; i < res2.fruits_count; i++) {
        free(res2.fruits[i]);
    }
    free(res2.fruits);
    cJSON_Delete(json_res2);

    return 0;
}

This C program demonstrates JSON encoding and decoding using the cJSON library. Here’s a breakdown of what it does:

  1. We define structs Response1 and Response2 to represent our custom data types.

  2. We encode basic data types (boolean, integer, float, string) to JSON strings using cJSON functions.

  3. We encode slices (arrays in C) and maps (objects in C) to JSON.

  4. We encode a custom data type (Response1) to JSON.

  5. We decode a JSON string into a C structure, accessing its fields.

  6. We decode a JSON string into our custom data type (Response2).

  7. Throughout the program, we print the JSON strings and parsed values.

  8. We perform proper memory management, freeing allocated resources.

To compile and run this program, you’ll need to:

  1. Install the cJSON library (you can find it on GitHub).
  2. Compile the program with the cJSON library linked:
$ gcc -o json_example json_example.c -lcjson
$ ./json_example

This will output the JSON strings and parsed values, demonstrating both encoding and decoding of JSON in C.

Note that C doesn’t have built-in support for JSON, so we use a third-party library (cJSON in this case). The concepts are similar to the Go example, but the implementation details differ due to C’s lower-level nature and lack of built-in JSON support.