cJSON

repository·master·Indexed 12 days ago

https://github.com/davegamble/cjson

An ultralightweight JSON parser written in ANSI C (C89) designed for simplicity and ease of integration. It provides a set of functions for parsing JSON strings into a tree structure using the cJSON struct, as well as utilities for creating, managing, and printing JSON data. Supports build systems including CMake, Meson, and Vcpkg.

Tokens
1.9K
Snippets
6
Records
7
Agent score
46%

What's inside cJSON

  1. Understand the cJSON data structure

    master

    cJSON represents JSON values using the cJSON struct. Each item is a node in a linked list (for arrays and objects) or a standalone value.

    Key Fields:

    • next / prev: Pointers for linked list traversal.
    • child: Pointer to the first child (used for objects and arrays).
    • type: A bit-flag representing the JSON type.
    • valuestring: A zero-terminated string for cJSON_String or cJSON_Raw types.
    • valueint: Integer representation of a number.
    • valuedouble: Double representation of a number.
    • string: The key name for items within a cJSON_Object.

    Important: Type Checking Because type is a bit-flag, you must not use direct equality comparisons (e.g., item->type == cJSON_Number). Instead, use the provided cJSON_Is... functions (e.g., cJSON_IsNumber(item)), which handle NULL checks and bit-flag logic correctly.

    typedef struct cJSON
    {
        struct cJSON *next;
        struct cJSON *prev;
        struct cJSON *child;
        int type;
        char *valuestring;
        int valueint;
        double valuedouble;
        char *string;
    } cJSON;
  2. Include cJSON in your C project

    master

    If you have installed cJSON via CMake or a Makefile, include the header using the following path:

    #include <cjson/cJSON.h>

    If you copied the source files directly into your project, include them relative to your source directory (e.g., #include "cJSON.h").

    #include <cjson/cJSON.h>
  3. Install and build cJSON

    master

    cJSON can be integrated into your project using several methods:

    1. Copying Source (Simplest)

    Since the library consists of only cJSON.h and cJSON.c, you can simply copy these files directly into your project's source tree. It is written in ANSI C (C89) for maximum compatibility.

    2. Using CMake

    CMake (version 3.5+) is the recommended way to build cJSON. It is best to perform an out-of-tree build:

    mkdir build
    cd build
    cmake ..
    make

    To install the library to your system, run make install. By default, headers are placed in /usr/local/include/cjson and libraries in /usr/local/lib.

    Common CMake Options:

    • -DENABLE_CJSON_UTILS=On: Enables cJSON_Utils.
    • -DENABLE_CJSON_TEST=On: Enables building tests (default).
    • -DBUILD_SHARED_LIBS=On: Builds shared libraries (default).
    • -DCMAKE_INSTALL_PREFIX=/path: Sets the installation prefix.

    3. Using Meson

    In a Meson project, include libcjson as a dependency:

    project('c-json-example', 'c')
    cjson = dependency('libcjson')
    
    example = executable(
        'example',
        'example.c',
        dependencies: [cjson],
    )

    4. Using Vcpkg

    ./vcpkg install cjson
    mkdir build
    cd build
    cmake ..
    make
  4. Create and manage cJSON items

    master

    cJSON provides cJSON_Create... functions for every JSON type. All these functions allocate memory on the heap.

    Creating Basic Types

    • Null: cJSON_CreateNull()
    • Booleans: cJSON_CreateTrue(), cJSON_CreateFalse(), or cJSON_CreateBool()
    • Numbers: cJSON_CreateNumber(double) (sets both valuedouble and valueint)
    • Strings:
      • cJSON_CreateString(const char *str): Copies the string.
      • cJSON_CreateStringReference(const char *str): Points directly to the string (you are responsible for its lifetime).

    Arrays and Objects

    • Arrays: cJSON_CreateArray(), cJSON_CreateArrayReference()
    • Objects: cJSON_CreateObject(), cJSON_CreateObjectReference()

    Memory Management and Ownership

    Crucial Rule: When you add an item to an array or an object (using functions like cJSON_AddItemToArray or cJSON_AddItemToObject), ownership is transferred to the parent container.

    • Do NOT call cJSON_Delete() on an item that has been added to a parent.
    • DO call cJSON_Delete() on the root object/array to free the entire tree.
    • To remove an item without deleting it, use cJSON_DetachItemFromArray or cJSON_DetachItemFromObjectCaseSensitive and assign the result to a pointer to prevent memory leaks.
    cJSON *root = cJSON_CreateObject();
    cJSON *name = cJSON_CreateString("Example");
    cJSON_AddItemToObject(root, "name", name); // Ownership transferred to root
    
    cJSON_Delete(root); // This will also delete 'name'
    // name is now invalid; do not use it.
  5. Parse JSON strings

    master

    To convert a JSON string into a cJSON tree structure, use the following functions:

    • Zero-terminated strings: cJSON_Parse(const char *value)
    • Strings with known length: cJSON_ParseWithLength(const char *value, size_t length)

    Error Handling

    If parsing fails, cJSON_Parse returns NULL. You can retrieve the position of the error using cJSON_GetErrorPtr().

    For thread-safe error handling, use cJSON_ParseWithOpts. By passing a pointer to the return_parse_end parameter, the function will populate it with the end of the parsed JSON or the error position, avoiding the global state used by cJSON_GetErrorPtr.

    cJSON *json = cJSON_Parse(input_string);
    if (json == NULL) {
        const char *error_ptr = cJSON_GetErrorPtr();
        // handle error
    }
  6. Print cJSON trees to strings

    master

    To convert a cJSON structure back into a string, use the printing functions. Note: You are responsible for freeing the returned string.

    • Formatted (with whitespace): cJSON_Print(const cJSON *item)
    • Unformatted (compact): cJSON_PrintUnformatted(const cJSON *item)
    • Buffered (with pre-allocated size): cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
    • Pre-allocated buffer: cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)

    Example:

    cJSON *root = cJSON_CreateObject();
    // ... populate root ...
    char *string = cJSON_Print(root);
    printf("%s\n", string);
    free(string); // Must free the string!
    cJSON_Delete(root);
    char *string = cJSON_Print(json_tree);
    if (string != NULL) {
        printf("%s\n", string);
        free(string);
    }
  7. Reference: cJSON Data Types and Type Checking

    master

    The following table lists the available JSON types in cJSON and the corresponding functions used to check for them. Note that type is a bit-flag, so always use the cJSON_Is... functions.

    TypeCheck FunctionDescription
    cJSON_InvalidcJSON_IsInvalidInvalid item (e.g., zeroed memory)
    cJSON_FalsecJSON_IsFalseBoolean false
    cJSON_TruecJSON_IsTrueBoolean true
    cJSON_NULLcJSON_IsNullJSON null
    cJSON_NumbercJSON_IsNumberNumber (stored as double/int)
    cJSON_StringcJSON_IsStringString (zero-terminated)
    cJSON_ArraycJSON_IsArrayArray (linked list of items)
    cJSON_ObjectcJSON_IsObjectObject (linked list of items with keys)
    cJSON_RawcJSON_IsRawRaw character array (not created by parser)
    cJSON_IsReferenceN/AFlag: Item does not own its child or valuestring
    cJSON_StringIsConstN/AFlag: string field points to a constant string