third_party_cJSON:基于 ANSI C 的超轻量级 JSON 解析器项目

Third-party open-source software cJSON | 三方开源软件cJSON

分支304Tags64
文件最后提交记录最后更新时间
5 年前
5 年前
5 年前
5 年前
3 个月前
5 年前
8 个月前
8 个月前
5 年前
1 年前
8 个月前
8 个月前
2 年前
5 年前
8 个月前
5 年前
4 年前
8 个月前
1 年前
5 年前
6 个月前
3 个月前
8 个月前
10 个月前
5 年前
5 年前
5 年前

cJSON

采用 ANSI C 编写的超轻量级 JSON 解析器。

目录

许可证

MIT 许可证

版权所有 (c) 2009-2017 Dave Gamble 与 cJSON 贡献者

特此免费授予任何获得本软件及相关文档文件(以下简称“软件”)副本的人,不受限制地处理软件的权利,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售软件副本的权利,并允许向其提供软件的人做出同样的行为,但须满足以下条件:

上述版权声明和本许可声明应包含在软件的所有副本或主要部分中。

本软件按“原样”提供,不提供任何明示或暗示的担保,包括但不限于对适销性、特定用途适用性和非侵权性的担保。在任何情况下,作者或版权持有人均不对因软件或软件的使用或其他交易而产生的任何索赔、损害或其他责任承担责任,无论是基于合同、侵权还是其他行为。

使用方法

欢迎使用 cJSON

cJSON 的目标是成为能帮你完成工作的、最简单的解析器。它仅包含一个 C 文件和一个头文件。

JSON 的最佳描述参见:http://www.json.org/ 。它类似 XML,但更为精简。你可以用它来传输数据、存储信息,或者表示程序的状态。

作为一个库,cJSON 旨在尽可能减少你的工作负担,同时又不造成干扰。为便于理解(此处简化说明),你可以通过两种模式使用它:自动模式和手动模式。下面快速介绍一下。

我从这个页面引用了一些 JSON 示例:http://www.json.org/fatfree.html 。正是这个页面启发我编写了 cJSON——一个力求与 JSON 本身理念一致的解析器:简单、直接、不添乱。

构建

有多种方式可将 cJSON 集成到你的项目中。

复制源代码

由于整个库仅包含一个 C 文件和一个头文件,你只需将 cJSON.hcJSON.c 复制到项目源代码中即可开始使用。

cJSON 采用 ANSI C(C89)编写,以支持尽可能多的平台和编译器。

CMake

借助 CMake,cJSON 支持完整的构建系统,从而能使用其全部功能。支持 CMake 2.8.5 及更高版本。推荐使用 CMake 进行外部构建,即编译文件会被放置在与源代码分离的目录中。因此,要在类 Unix 平台上使用 CMake 构建 cJSON,需创建一个 build 目录并在其中运行 CMake。

mkdir build
cd build
cmake ..

这将创建一个 Makefile 和一系列其他文件。之后你可以进行编译:

make

如果需要,您可以使用 make install 命令进行安装。默认情况下,头文件会安装到 /usr/local/include/cjson,库文件会安装到 /usr/local/lib。同时,安装程序还会部署 pkg-config 相关文件,以便更轻松地检测和使用现有的 CMake 安装。此外,它还会安装 CMake 配置文件,供其他基于 CMake 的项目发现该库。

您可以通过向 CMake 传递一系列不同的选项来更改构建过程。使用 On 启用选项,使用 Off 禁用选项:

  • -DENABLE_CJSON_TEST=On:启用测试构建。(默认开启)
  • -DENABLE_CJSON_UTILS=On:启用 cJSON_Utils 构建。(默认关闭)
  • -DENABLE_TARGET_EXPORT=On:启用 CMake 目标的导出功能。如果出现问题,请关闭此选项。(默认开启)
  • -DENABLE_CUSTOM_COMPILER_FLAGS=On:启用自定义编译器标志(目前支持 Clang、GCC 和 MSVC)。如果出现问题,请关闭此选项。(默认开启)
  • -DENABLE_VALGRIND=On:使用 valgrind 运行测试。(默认关闭)
  • -DENABLE_SANITIZERS=On:编译 cJSON 时启用 AddressSanitizerUndefinedBehaviorSanitizer(如果可能)。(默认关闭)
  • -DENABLE_SAFE_STACK:启用 SafeStack instrumentation 过程。目前仅适用于 Clang 编译器。(默认关闭)
  • -DBUILD_SHARED_LIBS=On:构建共享库。(默认开启)
  • -DBUILD_SHARED_AND_STATIC_LIBS=On:同时构建共享库和静态库。(默认关闭)
  • -DCMAKE_INSTALL_PREFIX=/usr:设置安装前缀。
  • -DENABLE_LOCALES=On:启用 localeconv 方法的使用。(默认开启)
  • -DCJSON_OVERRIDE_BUILD_SHARED_LIBS=On:允许通过 -DCJSON_BUILD_SHARED_LIBS 覆盖 BUILD_SHARED_LIBS 的值。
  • -DENABLE_CJSON_VERSION_SO:启用 cJSON 的 so 版本控制。(默认开启)

如果您要为 Linux 发行版打包 cJSON,例如,您可能会采取以下步骤:

mkdir build
cd build
cmake .. -DENABLE_CJSON_UTILS=On -DENABLE_CJSON_TEST=Off -DCMAKE_INSTALL_PREFIX=/usr
make
make DESTDIR=$pkgdir install

在 Windows 系统上,通常通过在 Visual Studio 的开发人员命令提示符中运行 CMake 来创建 Visual Studio 解决方案文件。有关具体步骤,请参考 CMake 和 Microsoft 的官方文档,并使用您偏好的在线搜索引擎获取帮助。上述选项的描述通常仍然适用,不过并非所有选项在 Windows 上都能正常工作。

Makefile

注意: 此方法已弃用。请尽可能使用 CMake。Makefile 仅支持修复错误。

如果您没有 CMake,但拥有 GNU make,那么可以使用 makefile 来构建 cJSON:

在包含源代码的目录中运行以下命令,它将自动编译静态库、共享库以及一个小型测试程序(并非完整的测试套件)。

make all

如果需要,您可以使用 make install 命令将编译好的库安装到系统中。默认情况下,头文件会安装到 /usr/local/include/cjson,库文件会安装到 /usr/local/lib。不过,您可以通过设置 PREFIXDESTDIR 变量来更改此行为,例如:make PREFIX=/usr DESTDIR=temp install。卸载时使用命令:make PREFIX=/usr DESTDIR=temp uninstall

Meson

要在使用 meson 的项目中使用 cjson,必须包含 libcjson 依赖:

project('c-json-example', 'c')

cjson = dependency('libcjson')

example = executable(
    'example',
    'example.c',
    dependencies: [cjson],
)

Vcpkg

您可以使用 vcpkg 依赖管理器下载并安装 cJSON:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
vcpkg install cjson

vcpkg 中的 cJSON 移植版本由 Microsoft 团队成员和社区贡献者负责更新。如果版本已过时,请在 vcpkg 代码库上创建 issue 或拉取请求

包含 cJSON

如果您通过 CMake 或 Makefile 安装了它,可以像这样包含 cJSON:

#include <cjson/cJSON.h>

数据结构

cJSON 使用 cJSON 结构体数据类型来表示 JSON 数据:

/* The cJSON structure: */
typedef struct cJSON
{
    struct cJSON *next;
    struct cJSON *prev;
    struct cJSON *child;
    int type;
    char *valuestring;
    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    int valueint;
    double valuedouble;
    char *string;
} cJSON;

此类项表示一个 JSON 值。类型以位标志的形式存储在 type 中(这意味着您不能仅通过比较 type 的值来确定类型)。

要检查项的类型,请使用相应的 cJSON_Is... 函数。它会先进行 NULL 检查,然后进行类型检查,如果该项是此类型,则返回布尔值。

类型可以是以下之一:

  • cJSON_Invalid(使用 cJSON_IsInvalid 检查):表示不包含任何值的无效项。如果将该项设置为全零字节,您会自动得到此类型。
  • cJSON_False(使用 cJSON_IsFalse 检查):表示 false 布尔值。您也可以使用 cJSON_IsBool 总体检查布尔值。
  • cJSON_True(使用 cJSON_IsTrue 检查):表示 true 布尔值。您也可以使用 cJSON_IsBool 总体检查布尔值。
  • cJSON_NULL(使用 cJSON_IsNull 检查):表示 null 值。
  • cJSON_Number(使用 cJSON_IsNumber 检查):表示数字值。该值以双精度浮点数形式存储在 valuedouble 中,同时也存储在 valueint 中。如果数字超出整数范围,则 valueint 会使用 INT_MAXINT_MIN
  • cJSON_String(使用 cJSON_IsString 检查):表示字符串值。它以以零结尾的字符串形式存储在 valuestring 中。
  • cJSON_Array(使用 cJSON_IsArray 检查):表示数组值。其实现方式是将 child 指向一个 cJSON 项的链表,这些项代表数组中的值。元素通过 nextprev 链接在一起,其中第一个元素的 prev.next == NULL,最后一个元素的 next == NULL
  • cJSON_Object(使用 cJSON_IsObject 检查):表示对象值。对象的存储方式与数组相同,唯一的区别是对象中的项将其键存储在 string 中。
  • cJSON_Raw(使用 cJSON_IsRaw 检查):表示以以零结尾的字符数组形式存储在 valuestring 中的任何类型的 JSON。例如,这可用于避免反复打印相同的静态 JSON 以节省性能。cJSON 在解析时绝不会创建此类型。另请注意,cJSON 不会检查它是否为有效的 JSON。

此外,还有以下两个标志:

  • cJSON_IsReference:指定 child 指向的项和/或 valuestring 不由该项拥有,而仅是一个引用。因此,cJSON_Delete 和其他函数将仅释放此项,而不会释放其 child/valuestring
  • cJSON_StringIsConst:表示 string 指向一个常量字符串。这意味着 cJSON_Delete 和其他函数不会尝试释放 string

使用数据结构

对于每种值类型,都有一个 cJSON_Create... 函数可用于创建该类型的项。 所有这些函数都会分配一个 cJSON 结构体,之后可通过 cJSON_Delete 进行删除。 请注意,必须在某个时候删除它们,否则会导致内存泄漏。
重要:如果已将某个项添加到数组或对象中,则不得使用 cJSON_Delete 删除它。将其添加到数组或对象后,所有权随之转移,因此当该数组或对象被删除时,该项也会被一并删除。你也可以使用 cJSON_SetValuestring 来更改 cJSON_Stringvaluestring,无需手动释放之前的 valuestring

基本类型

  • null 通过 cJSON_CreateNull 创建
  • 布尔值 通过 cJSON_CreateTruecJSON_CreateFalsecJSON_CreateBool 创建
  • 数字 通过 cJSON_CreateNumber 创建。这会同时设置 valuedoublevalueint。如果数字超出整数范围,则 valueint 会使用 INT_MAXINT_MIN
  • 字符串 通过 cJSON_CreateString(复制字符串)或 cJSON_CreateStringReference(直接指向字符串)创建。使用后者意味着 valuestring 不会被 cJSON_Delete 删除,你需要自行管理其生命周期,这对于常量非常有用

数组

可以使用 cJSON_CreateArray 创建空数组。cJSON_CreateArrayReference 可用于创建不“拥有”其内容的数组,因此其内容不会被 cJSON_Delete 删除。

要向数组添加项,使用 cJSON_AddItemToArray 在末尾追加项。 使用 cJSON_AddItemReferenceToArray 可以将一个元素作为对另一个项、数组或字符串的引用添加进来。这意味着 cJSON_Delete 不会删除该项的 childvaluestring 属性,因此如果它们已在其他地方使用,也不会发生双重释放。 要在数组中间插入项,使用 cJSON_InsertItemInArray。它会在指定的从 0 开始的索引处插入项,并将所有现有项向右移动。

如果要从数组的指定索引处取出一项并继续使用,可使用 cJSON_DetachItemFromArray,它会返回被分离的项,因此务必将其赋值给一个指针,否则会导致内存泄漏。

使用 cJSON_DeleteItemFromArray 删除项。其工作方式类似于 cJSON_DetachItemFromArray,但会通过 cJSON_Delete 删除被分离的项。

你也可以在数组中原地替换项。可以使用 cJSON_ReplaceItemInArray 通过索引进行替换,或者使用 cJSON_ReplaceItemViaPointer 给定指向某个元素的指针进行替换。cJSON_ReplaceItemViaPointer 失败时会返回 0。其内部操作是分离旧项、删除旧项并在原位置插入新项。

要获取数组的大小,使用 cJSON_GetArraySize。使用 cJSON_GetArrayItem 获取指定索引处的元素。

由于数组是以链表形式存储的,通过索引迭代效率较低(O(n²)),因此你可以使用 cJSON_ArrayForEach 宏以 O(n) 的时间复杂度迭代数组。

对象

可以使用 cJSON_CreateObject 创建空对象。cJSON_CreateObjectReference 可用于创建不“拥有”其内容的对象,因此其内容不会被 cJSON_Delete 删除。

要向对象添加项,使用 cJSON_AddItemToObject。使用 cJSON_AddItemToObjectCS 可将项添加到对象中,其名称为常量或引用(即项的键,cJSON 结构体中的 string),因此不会被 cJSON_Delete 释放。 使用 cJSON_AddItemReferenceToArray 可以将一个元素作为对另一个对象、数组或字符串的引用添加进来。这意味着 cJSON_Delete 不会删除该项的 childvaluestring 属性,因此如果它们已在其他地方使用,也不会发生双重释放。

如果要从对象中取出一项,使用 cJSON_DetachItemFromObjectCaseSensitive,它会返回被分离的项,因此务必将其赋值给一个指针,否则会导致内存泄漏。

使用 cJSON_DeleteItemFromObjectCaseSensitive 删除项。其工作方式类似于 cJSON_DetachItemFromObjectCaseSensitive 后接 cJSON_Delete

你也可以在对象中原地替换项。可以使用 cJSON_ReplaceItemInObjectCaseSensitive 通过键进行替换,或者使用 cJSON_ReplaceItemViaPointer 给定指向某个元素的指针进行替换。cJSON_ReplaceItemViaPointer 失败时会返回 0。其内部操作是分离旧项、删除旧项并在原位置插入新项。

要获取对象的大小,可以使用 cJSON_GetArraySize,这是因为对象在内部是作为数组存储的。

如果要访问对象中的项,使用 cJSON_GetObjectItemCaseSensitive

要迭代对象,可以像迭代数组一样使用 cJSON_ArrayForEach 宏。

cJSON 还提供了便捷的辅助函数,用于快速创建新项并将其添加到对象中,例如 cJSON_AddNullToObject。这些函数返回指向新项的指针,失败时返回 NULL

解析 JSON

如果有一个以空字符结尾的字符串形式的 JSON 数据,您可以使用 cJSON_Parse 对其进行解析。

cJSON *json = cJSON_Parse(string);

若字符串中包含 JSON 数据(无论是否以零结尾),您可以使用 cJSON_ParseWithLength 对其进行解析。

cJSON *json = cJSON_ParseWithLength(string, buffer_length);

它会解析 JSON 并分配一个表示该 JSON 的 cJSON 项树。一旦返回,您需要在使用后通过 cJSON_Delete 对其进行释放,对此负全部责任。

cJSON_Parse 默认使用 mallocfree 作为分配器,但可以通过 cJSON_InitHooks(全局地)进行更改。

如果发生错误,可以使用 cJSON_GetErrorPtr 获取指向输入字符串中错误位置的指针。但请注意,这在多线程场景下可能会产生竞争条件,在这种情况下,最好使用带有 return_parse_endcJSON_ParseWithOpts。默认情况下,输入字符串中位于已解析 JSON 之后的字符不会被视为错误。

如果您需要更多选项,请使用 cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)return_parse_end 会返回一个指针,指向输入字符串中 JSON 的结尾处或发生错误的位置(从而以线程安全的方式替代 cJSON_GetErrorPtr)。如果 require_null_terminated 设为 1,那么当输入字符串在 JSON 之后包含数据时,将被视为错误。

如果您需要更多选项,包括指定缓冲区长度,请使用 cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)

打印 JSON

对于一个 cJSON 项树,您可以使用 cJSON_Print 将其打印为字符串。

char *string = cJSON_Print(json);

它会分配一个字符串,并将 JSON 树的表示形式打印到该字符串中。一旦返回,你需要完全负责在使用后通过分配器释放它(通常是 free,具体取决于 cJSON_InitHooks 的设置)。

cJSON_Print 会打印带有空白字符的格式化 JSON。如果你想打印不带格式的 JSON,请使用 cJSON_PrintUnformatted

如果你大致了解结果字符串的大小,可以使用 cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)fmt 是一个布尔值,用于开启或关闭带空白字符的格式化功能。prebuffer 指定打印时使用的初始缓冲区大小。cJSON_Print 当前使用 256 字节作为其初始缓冲区大小。当打印空间不足时,会分配一个新的缓冲区,复制旧缓冲区的内容后继续打印。

使用 cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) 可以完全避免这些动态缓冲区分配。它接受一个指向待打印缓冲区的指针及其长度。如果达到该长度,打印将失败并返回 0。成功时则返回 1。注意,你应该提供比实际需要多 5 个字节的空间,因为 cJSON 在估算所需内存是否足够时并非 100% 准确。

示例

在本示例中,我们想要构建并解析以下 JSON:

{
    "name": "Awesome 4K",
    "resolutions": [
        {
            "width": 1280,
            "height": 720
        },
        {
            "width": 1920,
            "height": 1080
        },
        {
            "width": 3840,
            "height": 2160
        }
    ]
}

打印

我们来构建上述 JSON 并将其打印为字符串:

//create a monitor with a list of supported resolutions
//NOTE: Returns a heap allocated string, you are required to free it after use.
char *create_monitor(void)
{
    const unsigned int resolution_numbers[3][2] = {
        {1280, 720},
        {1920, 1080},
        {3840, 2160}
    };
    char *string = NULL;
    cJSON *name = NULL;
    cJSON *resolutions = NULL;
    cJSON *resolution = NULL;
    cJSON *width = NULL;
    cJSON *height = NULL;
    size_t index = 0;

    cJSON *monitor = cJSON_CreateObject();
    if (monitor == NULL)
    {
        goto end;
    }

    name = cJSON_CreateString("Awesome 4K");
    if (name == NULL)
    {
        goto end;
    }
    /* after creation was successful, immediately add it to the monitor,
     * thereby transferring ownership of the pointer to it */
    cJSON_AddItemToObject(monitor, "name", name);

    resolutions = cJSON_CreateArray();
    if (resolutions == NULL)
    {
        goto end;
    }
    cJSON_AddItemToObject(monitor, "resolutions", resolutions);

    for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
    {
        resolution = cJSON_CreateObject();
        if (resolution == NULL)
        {
            goto end;
        }
        cJSON_AddItemToArray(resolutions, resolution);

        width = cJSON_CreateNumber(resolution_numbers[index][0]);
        if (width == NULL)
        {
            goto end;
        }
        cJSON_AddItemToObject(resolution, "width", width);

        height = cJSON_CreateNumber(resolution_numbers[index][1]);
        if (height == NULL)
        {
            goto end;
        }
        cJSON_AddItemToObject(resolution, "height", height);
    }

    string = cJSON_Print(monitor);
    if (string == NULL)
    {
        fprintf(stderr, "Failed to print monitor.\n");
    }

end:
    cJSON_Delete(monitor);
    return string;
}

或者,我们可以使用 cJSON_Add...ToObject 辅助函数来让操作更便捷一些:

//NOTE: Returns a heap allocated string, you are required to free it after use.
char *create_monitor_with_helpers(void)
{
    const unsigned int resolution_numbers[3][2] = {
        {1280, 720},
        {1920, 1080},
        {3840, 2160}
    };
    char *string = NULL;
    cJSON *resolutions = NULL;
    size_t index = 0;

    cJSON *monitor = cJSON_CreateObject();

    if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL)
    {
        goto end;
    }

    resolutions = cJSON_AddArrayToObject(monitor, "resolutions");
    if (resolutions == NULL)
    {
        goto end;
    }

    for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
    {
        cJSON *resolution = cJSON_CreateObject();

        if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL)
        {
            goto end;
        }

        if (cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL)
        {
            goto end;
        }

        cJSON_AddItemToArray(resolutions, resolution);
    }

    string = cJSON_Print(monitor);
    if (string == NULL)
    {
        fprintf(stderr, "Failed to print monitor.\n");
    }

end:
    cJSON_Delete(monitor);
    return string;
}

解析

在此示例中,我们将解析上述格式的 JSON,并在打印一些诊断输出的同时,检查显示器是否支持全高清分辨率:

/* return 1 if the monitor supports full hd, 0 otherwise */
int supports_full_hd(const char * const monitor)
{
    const cJSON *resolution = NULL;
    const cJSON *resolutions = NULL;
    const cJSON *name = NULL;
    int status = 0;
    cJSON *monitor_json = cJSON_Parse(monitor);
    if (monitor_json == NULL)
    {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL)
        {
            fprintf(stderr, "Error before: %s\n", error_ptr);
        }
        status = 0;
        goto end;
    }

    name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name");
    if (cJSON_IsString(name) && (name->valuestring != NULL))
    {
        printf("Checking monitor \"%s\"\n", name->valuestring);
    }

    resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions");
    cJSON_ArrayForEach(resolution, resolutions)
    {
        cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width");
        cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height");

        if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height))
        {
            status = 0;
            goto end;
        }

        if ((width->valuedouble == 1920) && (height->valuedouble == 1080))
        {
            status = 1;
            goto end;
        }
    }

end:
    cJSON_Delete(monitor_json);
    return status;
}

请注意,除了 cJSON_Parse 的结果外,没有其他 NULL 检查,因为 cJSON_GetObjectItemCaseSensitive 已对 NULL 输入进行了检查,所以 NULL 值会直接传播,并且如果输入为 NULL,cJSON_IsNumbercJSON_IsString 会返回 0。

注意事项

零字符

cJSON 不支持包含零字符 '\0'\u0000 的字符串。由于字符串是以零结尾的,因此当前 API 无法支持此类字符串。

字符编码

cJSON 仅支持 UTF-8 编码的输入。不过在大多数情况下,它不会拒绝无效的 UTF-8 作为输入,而是会原样传播。只要输入不包含无效的 UTF-8,输出就始终是有效的 UTF-8。

C 标准

cJSON 采用 ANSI C(即 C89、C90)编写。如果您的编译器或 C 库不遵循此标准,则无法保证其行为的正确性。

注意:ANSI C 并非 C++,因此不应使用 C++ 编译器进行编译。不过,您可以使用 C 编译器编译它,然后将其与 C++ 代码链接。尽管使用 C++ 编译器编译可能能够运行,但无法保证其行为的正确性。

浮点数

cJSON 官方仅支持 IEEE754 双精度浮点数,不支持其他 double 实现。虽然在其他实现上可能仍能运行,但由此产生的错误将不被视为有效问题。

cJSON 当前支持的浮点数字面量的最大长度为 63 个字符。

数组和对象的深度嵌套

cJSON 不支持嵌套过深的数组和对象,因为这会导致栈溢出。为防止这种情况,cJSON 将深度限制为 CJSON_NESTING_LIMIT,默认值为 1000,但可在编译时进行修改。

线程安全

通常情况下,cJSON 不是线程安全的

但在以下条件下是线程安全的:

  • 从不使用 cJSON_GetErrorPtr(可改用 cJSON_ParseWithOptsreturn_parse_end 参数)
  • cJSON_InitHooks 仅在任何线程中使用 cJSON 之前调用。
  • 在所有 cJSON 函数调用返回之前,从不调用 setlocale

大小写敏感性

cJSON 最初创建时并未遵循 JSON 标准,不对大小写字母进行区分。如果您需要符合标准的正确行为,则需要在可用时使用 CaseSensitive 函数。

重复的对象成员

cJSON 支持解析和打印包含具有相同名称的多个成员的对象的 JSON。但是,cJSON_GetObjectItemCaseSensitive 将始终只返回第一个成员。

欢迎使用 cJSON!

  • Dave Gamble(原作者)
  • Max Bruckner 与 Alan Wang(现任维护者)
  • 以及其他 cJSON 贡献者

项目介绍

Third-party open-source software cJSON | 三方开源软件cJSON

定制我的领域