JSON基础:包括组包的概念等

Github:DaveGamble/cJSON

https://github.com/DaveGamble/cJSON

文章目录

  • Github:DaveGamble/cJSON
  • License
  • Usage
    • Welcome to cJSON.
    • Building
      • copying the source 复制源
      • CMake
      • Makefile
      • Vcpkg
    • Including cJSON
    • Data Structure
    • Working with the data structure 使用数据结构
      • Basic types
      • Arrays
      • Objects
    • Parsing JSON 解析JSON串
    • Printing JSON 打印(遍历)JSON串
    • Example 示例
      • Printing 打印(序列化)发送端
        • vs上测试
      • Parsing 解析(反序列化)接收端
        • VS上测试(略)
    • Caveats 注意事项
      • Zero Character
      • Character Encoding
      • C Standard
      • Floating Point Numbers
      • Deep Nesting Of Arrays And Objects 数组和对象的深度嵌套
      • Thread Safety
      • Case Sensitivity
      • Duplicate Object Members 重复的对象成员

License

omitted

Usage

Welcome to cJSON.

cJSON aims to be the dumbest possible parser that you can get your job done with. It’s a single file of C, and a single header file.

JSON is described best here: http://www.json.org/ It’s like XML, but fat-free. You use it to move data around, store things, or just generally represent your program’s state.

As a library, cJSON exists to take away as much legwork as it can, but not get in your way. As a point of pragmatism (i.e. ignoring the truth), I’m going to say that you can use it in one of two modes: Auto and Manual. Let’s have a quick run-through.

I lifted some JSON from this page: http://www.json.org/fatfree.html That page inspired me to write cJSON, which is a parser that tries to share the same philosophy as JSON itself. Simple, dumb, out of the way.

cJSON 旨在成为您可以完成工作的最愚蠢的解析器。 它是 C 的单个文件和单个头文件。

JSON 在这里描述得最好:http://www.json.org/ 它类似于 XML,但没有脂肪(意指不含多余的东西)。 你用它来移动数据,存储东西,或者只是一般地代表你的程序的状态。

作为一个库,cJSON 的存在是为了带走尽可能多的跑腿工作,但不会妨碍您。 作为实用主义的一点(即忽略事实),我会说您可以在以下两种模式之一中使用它:自动和手动。 让我们快速浏览一下。

我从这个页面中提取了一些 JSON:http://www.json.org/fatfree.html 该页面启发了我编写 cJSON,它是一个尝试与 JSON 本身共享相同理念的解析器。 简单,愚蠢,不碍事。

Building

There are several ways to incorporate cJSON into your project.

有几种方法可以将 cJSON 合并到您的项目中。

copying the source 复制源

Because the entire library is only one C file and one header file, you can just copy cJSON.h and cJSON.c to your projects source and start using it.

cJSON is written in ANSI C (C89) in order to support as many platforms and compilers as possible.

因为整个库只有一个 C 文件和一个头文件,您只需将 cJSON.h 和 cJSON.c 复制到您的项目源并开始使用它即可。

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

CMake

With CMake, cJSON supports a full blown build system. This way you get the most features. CMake with an equal or higher version than 2.8.5 is supported. With CMake it is recommended to do an out of tree build, meaning the compiled files are put in a directory separate from the source files. So in order to build cJSON with CMake on a Unix platform, make a build directory and run CMake inside it.

使用 CMake,cJSON 支持完整的构建系统。 这样您就可以获得最多的功能。 支持版本等于或高于 2.8.5 的 CMake。 使用 CMake 建议进行树外构建,这意味着编译后的文件放在与源文件不同的目录中。 因此,为了在 Unix 平台上使用 CMake 构建 cJSON,创建一个构建目录并在其中运行 CMake。

mkdir build
cd build
cmake ..

This will create a Makefile and a bunch of other files. You can then compile it:

这将创建一个 Makefile 和一堆其他文件。 然后你可以编译它:

make

And install it with make install if you want. By default it installs the headers /usr/local/include/cjson and the libraries to /usr/local/lib. It also installs files for pkg-config to make it easier to detect and use an existing installation of CMake. And it installs CMake config files, that can be used by other CMake based projects to discover the library.

You can change the build process with a list of different options that you can pass to CMake. Turn them on with On and off with Off:

如果需要,可以使用 make install 安装它。 默认情况下,它将头文件 /usr/local/include/cjson 和库安装到 /usr/local/lib。 它还为 pkg-config 安装文件,以便更容易检测和使用现有的 CMake 安装。 它会安装 CMake 配置文件,其他基于 CMake 的项目可以使用这些文件来发现库。

您可以使用可以传递给 CMake 的不同选项列表来更改构建过程。 用 On 打开它们,用 Off 关闭它们:

  • DENABLE_CJSON_TEST=On: Enable building the tests. (on by default)
  • DENABLE_CJSON_UTILS=On: Enable building cJSON_Utils. (off by default)
  • DENABLE_TARGET_EXPORT=On: Enable the export of CMake targets. Turn off if it makes problems. (on by default)
  • DENABLE_CUSTOM_COMPILER_FLAGS=On: Enable custom compiler flags (currently for Clang, GCC and MSVC). Turn off if it makes problems. (on by default)
  • DENABLE_VALGRIND=On: Run tests with valgrind. (off by default)
  • DENABLE_SANITIZERS=On: Compile cJSON with AddressSanitizer and UndefinedBehaviorSanitizer enabled (if possible). (off by default)
  • DENABLE_SAFE_STACK: Enable the SafeStack instrumentation pass. Currently only works with the Clang compiler. (off by default)
  • DBUILD_SHARED_LIBS=On: Build the shared libraries. (on by default)
  • DBUILD_SHARED_AND_STATIC_LIBS=On: Build both shared and static libraries. (off by default)
  • DCMAKE_INSTALL_PREFIX=/usr: Set a prefix for the installation.
  • DENABLE_LOCALES=On: Enable the usage of localeconv method. ( on by default )
  • DCJSON_OVERRIDE_BUILD_SHARED_LIBS=On: Enable overriding the value of BUILD_SHARED_LIBS with -DCJSON_BUILD_SHARED_LIBS.
  • DENABLE_CJSON_VERSION_SO: Enable cJSON so version. ( on by default )
    If you are packaging cJSON for a distribution of Linux, you would probably take these steps for example:
mkdir build
cd build
cmake .. -DENABLE_CJSON_UTILS=On -DENABLE_CJSON_TEST=Off -DCMAKE_INSTALL_PREFIX=/usr
make
make DESTDIR=$pkgdir install

On Windows CMake is usually used to create a Visual Studio solution file by running it inside the Developer Command Prompt for Visual Studio, for exact steps follow the official documentation from CMake and Microsoft and use the online search engine of your choice. The descriptions of the the options above still generally apply, although not all of them work on Windows.

在 Windows 上,CMake 通常用于通过在 Visual Studio 的开发人员命令提示符中运行它来创建 Visual Studio 解决方案文件,具体步骤请遵循 CMake 和 Microsoft 的官方文档并使用您选择的在线搜索引擎。 上述选项的描述仍然普遍适用,尽管并非所有选项都适用于 Windows。

Makefile

NOTE: This Method is deprecated. Use CMake if at all possible. Makefile support is limited to fixing bugs.

If you don’t have CMake available, but still have GNU make. You can use the makefile to build cJSON:

Run this command in the directory with the source code and it will automatically compile static and shared libraries and a little test program (not the full test suite).

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

如果您没有可用的 CMake,但仍有 GNU make。 您可以使用 makefile 构建 cJSON:

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

make all

If you want, you can install the compiled library to your system using make install. By default it will install the headers in /usr/local/include/cjson and the libraries in /usr/local/lib. But you can change this behavior by setting the PREFIX and DESTDIR variables: make PREFIX=/usr DESTDIR=temp install. And uninstall them with: make PREFIX=/usr DESTDIR=temp uninstall.

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

Vcpkg

You can download and install cJSON using the vcpkg dependency manager:

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

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

The cJSON port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.

vcpkg 中的 cJSON 端口由 Microsoft 团队成员和社区贡献者保持最新。 如果版本过期,请在 vcpkg 存储库上创建问题或拉取请求。

Including cJSON

If you installed it via CMake or the Makefile, you can include cJSON like this:

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

#include <cjson/cJSON.h>

Data Structure

cJSON represents JSON data using the cJSON struct data type:

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;

An item of this type represents a JSON value. The type is stored in type as a bit-flag (this means that you cannot find out the type by just comparing the value of type).

To check the type of an item, use the corresponding cJSON_Is… function. It does a NULL check followed by a type check and returns a boolean value if the item is of this type.

The type can be one of the following:

此类型的项目表示 JSON 值。 类型作为位标志存储在类型中(这意味着您无法仅通过比较类型的值来找出类型)。

要检查项目的类型,请使用相应的 cJSON_Is… 函数。 它先进行 NULL 检查,然后进行类型检查,如果项目属于这种类型,则返回一个布尔值。

类型可以是以下之一:

  • cJSON_Invalid (check with cJSON_IsInvalid): Represents an invalid item that doesn’t contain any value. You automatically have this type if you set the item to all zero bytes.
  • cJSON_False (check with cJSON_IsFalse): Represents a false boolean value. You can also check for boolean values in general with cJSON_IsBool.
  • cJSON_True (check with cJSON_IsTrue): Represents a true boolean value. You can also check for boolean values in general with cJSON_IsBool.
  • cJSON_NULL (check with cJSON_IsNull): Represents a null value.
  • cJSON_Number (check with cJSON_IsNumber): Represents a number value. The value is stored as a double in valuedouble and also in valueint. If the number is outside of the range of an integer, INT_MAX or INT_MIN are used for valueint.
  • cJSON_String (check with cJSON_IsString): Represents a string value. It is stored in the form of a zero terminated string in valuestring.
  • cJSON_Array (check with cJSON_IsArray): Represent an array value. This is implemented by pointing child to a linked list of cJSON items that represent the values in the array. The elements are linked together using next and prev, where the first element has prev.next == NULL and the last element next == NULL.
  • cJSON_Object (check with cJSON_IsObject): Represents an object value. Objects are stored same way as an array, the only difference is that the items in the object store their keys in string.
  • cJSON_Raw (check with cJSON_IsRaw): Represents any kind of JSON that is stored as a zero terminated array of characters in valuestring. This can be used, for example, to avoid printing the same static JSON over and over again to save performance. cJSON will never create this type when parsing. Also note that cJSON doesn’t check if it is valid JSON.

  • cJSON_Invalid(使用 cJSON_IsInvalid 检查):表示不包含任何值的无效项。如果您将项目设置为全零字节,您将自动拥有此类型。
  • cJSON_False(检查 cJSON_IsFalse):表示一个假布尔值。您还可以使用 cJSON_IsBool 通常检查布尔值。
  • cJSON_True(检查 cJSON_IsTrue):表示一个真正的布尔值。您还可以使用 cJSON_IsBool 通常检查布尔值。
  • cJSON_NULL(检查 cJSON_IsNull):表示空值。
  • cJSON_Number(检查 cJSON_IsNumber):表示一个数字值。该值作为双精度值存储在 valuedouble 和 valueint 中。如果数字超出整数范围,则将 INT_MAX 或 INT_MIN 用于 valueint。
  • cJSON_String(检查 cJSON_IsString):表示一个字符串值。它以 valuestring 中以零结尾的字符串的形式存储。
  • cJSON_Array(检查 cJSON_IsArray):表示一个数组值。这是通过将 child 指向表示数组中的值的 cJSON 项的链接列表来实现的。元素使用 next 和 prev 链接在一起,其中第一个元素具有 prev.next == NULL,最后一个元素具有 next == NULL。
  • cJSON_Object(检查 cJSON_IsObject):表示一个对象值。对象的存储方式与数组相同,唯一的区别是对象中的项目将它们的键存储在字符串中。
  • cJSON_Raw(使用 cJSON_IsRaw 检查):表示任何类型的 JSON,存储为 valuestring 中以零结尾的字符数组。例如,这可以用来避免一遍又一遍地打印相同的静态 JSON 以节省性能。 cJSON 在解析时永远不会创建这种类型。另请注意,cJSON 不会检查它是否是有效的 JSON。

Additionally there are the following two flags:

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

  • cJSON_IsReference: Specifies that the item that child points to and/or valuestring is not owned by this item, it is only a reference. So cJSON_Delete and other functions will only deallocate this item, not its child/valuestring.

  • cJSON_StringIsConst: This means that string points to a constant string. This means that cJSON_Delete and other functions will not try to deallocate string.

  • cJSON_IsReference:指定 child 指向的项目和/或 valuestring 不属于该项目,它只是一个引用。 所以 cJSON_Delete 和其他函数只会释放这个 item,而不是它的 child/valuestring。

  • cJSON_StringIsConst:这意味着字符串指向一个常量字符串。 这意味着 cJSON_Delete 和其他函数不会尝试释放字符串。

Working with the data structure 使用数据结构

For every value type there is a cJSON_Create… function that can be used to create an item of that type. All of these will allocate a cJSON struct that can later be deleted with cJSON_Delete. Note that you have to delete them at some point, otherwise you will get a memory leak.
Important: If you have added an item to an array or an object already, you mustn’t delete it with cJSON_Delete. Adding it to an array or object transfers its ownership so that when that array or object is deleted, it gets deleted as well. You also could use cJSON_SetValuestring to change a cJSON_String’s valuestring, and you needn’t to free the previous valuestring manually.

对于每个值类型,都有一个 cJSON_Create… 函数可用于创建该类型的项目。 所有这些都将分配一个 cJSON 结构,以后可以使用 cJSON_Delete 删除该结构。 请注意,您必须在某些时候删除它们,否则您会出现内存泄漏。
重要提示:如果您已经将项目添加到数组或对象中,则不得使用 cJSON_Delete 将其删除。 将其添加到数组或对象会转移其所有权,因此当删除该数组或对象时,它也会被删除。 您也可以使用 cJSON_SetValuestring 来更改 cJSON_String 的 valuestring,并且您不需要手动释放以前的 valuestring。

Basic types

  • null is created with cJSON_CreateNull

  • booleans are created with cJSON_CreateTrue, cJSON_CreateFalse or cJSON_CreateBool

  • numbers are created with cJSON_CreateNumber. This will set both valuedouble and valueint. If the number is outside of the range of an integer, INT_MAX or INT_MIN are used for valueint

  • strings are created with cJSON_CreateString (copies the string) or with cJSON_CreateStringReference (directly points to the string. This means that valuestring won’t be deleted by cJSON_Delete and you are responsible for its lifetime, useful for constants)

  • 使用 cJSON_CreateNull 创建 null

  • 使用 cJSON_CreateTrue、cJSON_CreateFalse 或 cJSON_CreateBool 创建布尔值

  • 数字是用 cJSON_CreateNumber 创建的。 这将设置 valuedouble 和 valueint。 如果数字超出整数范围,则使用 INT_MAX 或 INT_MIN 作为 valueint

  • 使用 cJSON_CreateString(复制字符串)或使用 cJSON_CreateStringReference(直接指向字符串。这意味着 valuestring 不会被 cJSON_Delete 删除,并且您负责它的生命周期,对常量有用)创建字符串

Arrays

You can create an empty array with cJSON_CreateArray. cJSON_CreateArrayReference can be used to create an array that doesn’t “own” its content, so its content doesn’t get deleted by cJSON_Delete.

To add items to an array, use cJSON_AddItemToArray to append items to the end. Using cJSON_AddItemReferenceToArray an element can be added as a reference to another item, array or string. This means that cJSON_Delete will not delete that items child or valuestring properties, so no double frees are occurring if they are already used elsewhere. To insert items in the middle, use cJSON_InsertItemInArray. It will insert an item at the given 0 based index and shift all the existing items to the right.

If you want to take an item out of an array at a given index and continue using it, use cJSON_DetachItemFromArray, it will return the detached item, so be sure to assign it to a pointer, otherwise you will have a memory leak.

Deleting items is done with cJSON_DeleteItemFromArray. It works like cJSON_DetachItemFromArray, but deletes the detached item via cJSON_Delete.

You can also replace an item in an array in place. Either with cJSON_ReplaceItemInArray using an index or with cJSON_ReplaceItemViaPointer given a pointer to an element. cJSON_ReplaceItemViaPointer will return 0 if it fails. What this does internally is to detach the old item, delete it and insert the new item in its place.

To get the size of an array, use cJSON_GetArraySize. Use cJSON_GetArrayItem to get an element at a given index.

Because an array is stored as a linked list, iterating it via index is inefficient (O(n²)), so you can iterate over an array using the cJSON_ArrayForEach macro in O(n) time complexity.

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

要将项目添加到数组,请使用 cJSON_AddItemToArray 将项目附加到末尾。使用 cJSON_AddItemReferenceToArray 可以将元素添加为对另一个项目、数组或字符串的引用。这意味着 cJSON_Delete 不会删除该项目的子属性或 valuestring 属性,因此如果它们已在其他地方使用,则不会发生双重释放。要在中间插入项目,请使用 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) 的时间复杂度迭代数组。

Objects

You can create an empty object with cJSON_CreateObject. cJSON_CreateObjectReference can be used to create an object that doesn’t “own” its content, so its content doesn’t get deleted by cJSON_Delete.

To add items to an object, use cJSON_AddItemToObject. Use cJSON_AddItemToObjectCS to add an item to an object with a name that is a constant or reference (key of the item, string in the cJSON struct), so that it doesn’t get freed by cJSON_Delete. Using cJSON_AddItemReferenceToArray an element can be added as a reference to another object, array or string. This means that cJSON_Delete will not delete that items child or valuestring properties, so no double frees are occurring if they are already used elsewhere.

If you want to take an item out of an object, use cJSON_DetachItemFromObjectCaseSensitive, it will return the detached item, so be sure to assign it to a pointer, otherwise you will have a memory leak.

Deleting items is done with cJSON_DeleteItemFromObjectCaseSensitive. It works like cJSON_DetachItemFromObjectCaseSensitive followed by cJSON_Delete.

You can also replace an item in an object in place. Either with cJSON_ReplaceItemInObjectCaseSensitive using a key or with cJSON_ReplaceItemViaPointer given a pointer to an element. cJSON_ReplaceItemViaPointer will return 0 if it fails. What this does internally is to detach the old item, delete it and insert the new item in its place.

To get the size of an object, you can use cJSON_GetArraySize, this works because internally objects are stored as arrays.

If you want to access an item in an object, use cJSON_GetObjectItemCaseSensitive.

To iterate over an object, you can use the cJSON_ArrayForEach macro the same way as for arrays.

cJSON also provides convenient helper functions for quickly creating a new item and adding it to an object, like cJSON_AddNullToObject. They return a pointer to the new item or NULL if they failed.

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

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

如果你想从一个对象中取出一个item,使用cJSON_DetachItemFromObjectCaseSensitive,它会返回分离后的item,所以一定要给它赋值给一个指针,否则会出现内存泄漏。

使用 cJSON_DeleteItemFromObjectCaseSensitive 删除项目。它的工作方式类似于 cJSON_DetachItemFromObjectCaseSensitive 后跟 cJSON_Delete。

您还可以就地替换对象中的项目。使用 cJSON_ReplaceItemInObjectCaseSensitive 使用键或使用 cJSON_ReplaceItemViaPointer 给定指向元素的指针。如果失败,cJSON_ReplaceItemViaPointer 将返回 0。这在内部所做的是分离旧项目,将其删除并在其位置插入新项目。

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

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

要迭代对象,您可以使用 cJSON_ArrayForEach 宏,方法与数组相同。

cJSON 还提供了方便的帮助函数,用于快速创建新项目并将其添加到对象中,例如 cJSON_AddNullToObject。它们返回指向新项目的指针,如果失败则返回 NULL。

Parsing JSON 解析JSON串

Given some JSON in a zero terminated string, you can parse it with cJSON_Parse.

给定零终止字符串中的一些 JSON,您可以使用 cJSON_Parse 对其进行解析。

cJSON *json = cJSON_Parse(string);

Given some JSON in a string (whether zero terminated or not), you can parse it with cJSON_ParseWithLength.

给定字符串中的一些 JSON(无论是否以零结尾),您可以使用 cJSON_ParseWithLength 对其进行解析。

cJSON *json = cJSON_ParseWithLength(string, buffer_length);

It will parse the JSON and allocate a tree of cJSON items that represents it. Once it returns, you are fully responsible for deallocating it after use with cJSON_Delete.

The allocator used by cJSON_Parse is malloc and free by default but can be changed (globally) with cJSON_InitHooks.

If an error occurs a pointer to the position of the error in the input string can be accessed using cJSON_GetErrorPtr. Note though that this can produce race conditions in multithreading scenarios, in that case it is better to use cJSON_ParseWithOpts with return_parse_end. By default, characters in the input string that follow the parsed JSON will not be considered as an error.

If you want more options, use cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated). return_parse_end returns a pointer to the end of the JSON in the input string or the position that an error occurs at (thereby replacing cJSON_GetErrorPtr in a thread safe way). require_null_terminated, if set to 1 will make it an error if the input string contains data after the JSON.

If you want more options giving buffer length, use cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated).

它将解析 JSON 并分配代表它的 cJSON 项目树。一旦它返回,您将完全负责在与 cJSON_Delete 一起使用后释放它。

cJSON_Parse 使用的分配器是 malloc 并且默认情况下是释放的,但可以使用 cJSON_InitHooks (全局)更改。

如果发生错误,则可以使用 cJSON_GetErrorPtr 访问指向输入字符串中错误位置的指针。请注意,尽管这可能会在多线程场景中产生竞争条件,但在这种情况下,最好将 cJSON_ParseWithOpts 与 return_parse_end 一起使用。默认情况下,解析后的 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)

Printing JSON 打印(遍历)JSON串

Given a tree of cJSON items, you can print them as a string using cJSON_Print.

char *string = cJSON_Print(json);

It will allocate a string and print a JSON representation of the tree into it. Once it returns, you are fully responsible for deallocating it after use with your allocator. (usually free, depends on what has been set with cJSON_InitHooks).

cJSON_Print will print with whitespace for formatting. If you want to print without formatting, use cJSON_PrintUnformatted.

If you have a rough idea of how big your resulting string will be, you can use cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt). fmt is a boolean to turn formatting with whitespace on and off. prebuffer specifies the first buffer size to use for printing. cJSON_Print currently uses 256 bytes for its first buffer size. Once printing runs out of space, a new buffer is allocated and the old gets copied over before printing is continued.

These dynamic buffer allocations can be completely avoided by using cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format). It takes a buffer to a pointer to print to and its length. If the length is reached, printing will fail and it returns 0. In case of success, 1 is returned. Note that you should provide 5 bytes more than is actually needed, because cJSON is not 100% accurate in estimating if the provided memory is enough.

它将分配一个字符串并将树的 JSON 表示打印到其中。一旦它返回,您将完全负责在使用分配器后释放它。 (通常是释放的,取决于 cJSON_InitHooks 的设置)。

cJSON_Print 将打印带有空格以进行格式化。如果要在不格式化的情况下打印,请使用 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% 准确的。

Example 示例

In this example we want to build and parse the following JSON:

在此示例中,我们要构建和解析以下 JSON:

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

Printing 打印(序列化)发送端

Let’s build the above JSON and print it to a string:

让我们构建上面的 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;
}

Alternatively we can use the cJSON_Add…ToObject helper functions to make our lives a little easier:

或者,我们可以使用 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;
}

vs上测试

#pragma warning(disable : 4996)
#include <stdio.h>
//#include <string.h>
#include "cJSON.h"//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;
}char cameraID_[64] = "DS-2XA7247F-IZS20211230AACHJ33724864";
char algorithmName_[64] = "安全帽算法";
int algorithmCategory_ = 0;
char alarmMessage_[1024] = "NULL";
char alarmImage_[1024] = "/capture_picture/DS-2XA7247F-IZS20211230AACHJ33724864_202203290910102233.jpg";
char alarmTime_[64] = "2022-02-01 10:12:01";char* create_alarm_info(void) {char* string = NULL;cJSON* cameraID = NULL;cJSON* algorithmName = NULL;cJSON* algorithmCategory = NULL;cJSON* alarmMessage = NULL;cJSON* alarmImage = NULL;cJSON* alarmTime = NULL;cJSON* alarm_info = cJSON_CreateObject();if (alarm_info == NULL){goto end;}//1 cameraIDcameraID = cJSON_CreateString(cameraID_);if (cameraID == NULL){goto end;}cJSON_AddItemToObject(alarm_info, "cameraID", cameraID);//2 algorithmNamealgorithmName = cJSON_CreateString(algorithmName_);if (algorithmName == NULL){goto end;}cJSON_AddItemToObject(alarm_info, "algorithmName", algorithmName);//3 algorithmCategoryalgorithmCategory = cJSON_CreateNumber(algorithmCategory_);if (algorithmCategory == NULL){goto end;}cJSON_AddItemToObject(alarm_info, "algorithmCategory", algorithmCategory);//4 alarmMessagealarmMessage = cJSON_CreateString(alarmMessage_);if (alarmMessage == NULL){goto end;}cJSON_AddItemToObject(alarm_info, "alarmMessage", alarmMessage);//5 alarmImagealarmImage = cJSON_CreateString(alarmImage_);if (alarmImage == NULL){goto end;}cJSON_AddItemToObject(alarm_info, "alarmImage", alarmImage);//6 alarmTimealarmTime = cJSON_CreateString(alarmTime_);if (alarmTime == NULL){goto end;}cJSON_AddItemToObject(alarm_info, "alarmTime", alarmTime);string = cJSON_Print(alarm_info);if (string == NULL){fprintf(stderr, "Failed to print alarm_info.\n");}end:cJSON_Delete(alarm_info);return string;
}int main() {char* s = create_monitor();printf("%s\n", s);free(s);printf("%s\n", s);  //乱码,说明函数返回的指针是malloc开辟的空间,用完指针必须free,否则可能导致内存溢出char* y = create_alarm_info();printf("%s\n", y);free(y);printf("%s\n", y);printf("%s\n", cameraID_);return 0;
}

运行结果:

{"name": "Awesome 4K","resolutions":  [{"width":        1280,"height":       720}, {"width":        1920,"height":       1080}, {"width":        3840,"height":       2160}]
}
葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺€
{"cameraID":     "DS-2XA7247F-IZS20211230AACHJ33724864","algorithmName":        "安全帽算法","algorithmCategory":    0,"alarmMessage": "NULL","alarmImage":   "/capture_picture/DS-2XA7247F-IZS20211230AACHJ33724864_202203290910102233.jpg","alarmTime":    "2022-02-01 10:12:01"
}
葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺屯屯屯?
DS-2XA7247F-IZS20211230AACHJ33724864

Parsing 解析(反序列化)接收端

In this example we will parse a JSON in the above format and check if the monitor supports a Full HD resolution while printing some diagnostic output:

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

/* return 1 if the monitor supports full hd, 0 otherwise 如果显示器支持全高清则返回 1,否则返回 0 */
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;
}

Note that there are no NULL checks except for the result of cJSON_Parse because cJSON_GetObjectItemCaseSensitive checks for NULL inputs already, so a NULL value is just propagated and cJSON_IsNumber and cJSON_IsString return 0 if the input is NULL.

请注意,除了 cJSON_Parse 的结果之外没有任何 NULL 检查,因为 cJSON_GetObjectItemCaseSensitive 已经检查了 NULL 输入,因此只是传播 NULL 值,如果输入为 NULL,则 cJSON_IsNumber 和 cJSON_IsString 返回 0。

VS上测试(略)

Caveats 注意事项

Zero Character

cJSON doesn’t support strings that contain the zero character ‘\0’ or \u0000. This is impossible with the current API because strings are zero terminated.

cJSON 不支持包含零字符 ‘\0’ 或 \u0000 的字符串。 这在当前的 API 中是不可能的,因为字符串是零终止的。

Character Encoding

cJSON only supports UTF-8 encoded input. In most cases it doesn’t reject invalid UTF-8 as input though, it just propagates it through as is. As long as the input doesn’t contain invalid UTF-8, the output will always be valid UTF-8.

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

C Standard

cJSON is written in ANSI C (or C89, C90). If your compiler or C library doesn’t follow this standard, correct behavior is not guaranteed.

NOTE: ANSI C is not C++ therefore it shouldn’t be compiled with a C++ compiler. You can compile it with a C compiler and link it with your C++ code however. Although compiling with a C++ compiler might work, correct behavior is not guaranteed.

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

注意:ANSI C 不是 C++,因此不应使用 C++ 编译器对其进行编译。 您可以使用 C 编译器对其进行编译,然后将其与您的 C++ 代码链接。 尽管使用 C++ 编译器进行编译可能会起作用,但不能保证正确的行为。

Floating Point Numbers

cJSON does not officially support any double implementations other than IEEE754 double precision floating point numbers. It might still work with other implementations but bugs with these will be considered invalid.

The maximum length of a floating point literal that cJSON supports is currently 63 characters.

cJSON 不正式支持除 IEEE754 双精度浮点数之外的任何双精度实现。 它可能仍然适用于其他实现,但这些错误将被视为无效。

cJSON 支持的浮点文字的最大长度目前为 63 个字符。

Deep Nesting Of Arrays And Objects 数组和对象的深度嵌套

cJSON doesn’t support arrays and objects that are nested too deeply because this would result in a stack overflow. To prevent this cJSON limits the depth to CJSON_NESTING_LIMIT which is 1000 by default but can be changed at compile time.

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

Thread Safety

In general cJSON is not thread safe.

However it is thread safe under the following conditions:

cJSON_GetErrorPtr is never used (the return_parse_end parameter of cJSON_ParseWithOpts can be used instead)
cJSON_InitHooks is only ever called before using cJSON in any threads.
setlocale is never called before all calls to cJSON functions have returned.

一般来说,cJSON 不是线程安全的。

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

cJSON_GetErrorPtr 从不使用(可以使用 cJSON_ParseWithOpts 的 return_parse_end 参数代替)
cJSON_InitHooks 只会在任何线程中使用 cJSON 之前被调用。
在所有对 cJSON 函数的调用都返回之前,永远不会调用 setlocale。

Case Sensitivity

When cJSON was originally created, it didn’t follow the JSON standard and didn’t make a distinction between uppercase and lowercase letters. If you want the correct, standard compliant, behavior, you need to use the CaseSensitive functions where available.

最初创建 cJSON 时,它没有遵循 JSON 标准,也没有区分大小写字母。 如果您想要正确的、符合标准的行为,则需要在可用的情况下使用 CaseSensitive 函数。

Duplicate Object Members 重复的对象成员

cJSON supports parsing and printing JSON that contains objects that have multiple members with the same name. cJSON_GetObjectItemCaseSensitive however will always only return the first one.

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

cJSON使用教程(树外构建 out of tree build 概念)(组包概念)相关推荐

  1. 使用GENBANK数据进行分子系统发育树的构建

    一.引言 GENBANK是目前最大而权威的分子序列数据库,调用其中数据可以进行分子系统发育树的构建. 1.序列数据获取(以皿蛛系统发育树为例) 在GenBank中,每一个物种或阶元都有一个taxid, ...

  2. DOM树和CSSOM树的构建和渲染

    页面的渲染过程 当我们在浏览器里输入一个 URL 后,最终会呈现一个完整的网页.会经历以下几个步骤: 1.HTML 的加载 页面上输入 URL 后,会先拿到 HTML 文件.HTML是一个页面的基础, ...

  3. 【算法学习笔记】哈夫曼树的构建和哈夫曼编码的实现代码

    介绍 哈夫曼(Haffman)这种方法的基本思想如下: ①由给定的n个权值{W1,W2,-,Wn}构造n棵只有一个叶子结点的二叉树,从而得到一个二叉树的集合F={T1,T2,-,Tn}. ②在F中选取 ...

  4. MEGA | 多序列比对及系统发育树的构建

    MEGA是一个用于多序列比对和可视化.以及构建系统发育树的免费程序.自1993年发布以来,MEGA共更新9个版本 (没有第八.九版),今年发布的MEGA 11为处理更大的数据集进行了优化. 之前我们介 ...

  5. MongoDB 教程番外篇之添加用户及设置用户权限 ( Rockmongo登陆设置 )

    继上一篇 MongoDB 教程番外篇之管理工具: Rockmongo ,MongoDB 缺省是没有设置鉴权的,业界大部分使用 MongoDB 的项目也没有设置访问权限.这就意味着只要知道 MongoD ...

  6. MongoDB 教程番外篇之管理工具: Rockmongo

    RockMongo是PHP5写的一个MongoDB管理工具. 通过 Rockmongo 你可以管理 MongoDB服务,数据库,集合,文档,索引等等. 它提供了非常人性化的操作.类似 phpMyAdm ...

  7. 分子动力学模拟软件_分子模拟软件Discovery Studio教程(十三):构建PLS模型(3D-QSAR)...

    Discovery Studio™ (简称DS)是专业的生命科学分子模拟软件,DS目前的主要功能包括:蛋白质的表征(包括蛋白-蛋白相互作用).同源建模.分子力学计算和分子动力学模拟.基于结构药物设计工 ...

  8. JAVA实现二叉树带权路径长度和_哈夫曼树的构建与最小带权路径长度

    注意:哈夫曼树并不唯一,但带权路径长度一定是相同的. 二叉树:每个结点最多含有两个子树的树称为二叉树. 定理:对于具有n个叶子结点的哈夫曼树,共有2n-1个结点. 哈夫曼树介绍 1哈夫曼树的定义 哈夫 ...

  9. 哈夫曼树的构建及哈夫曼树编码

    哈夫曼树的构建: 注意:(1).首先把一组数3 5 6 8 9 12 15从小到大排列 (2).选取里面最小2个,顶点出为2个数的和 (3).新产生的顶点在与原先的数字进行比较,在里面选取2个最小的数 ...

最新文章

  1. python3爬虫实例-自己动手,丰衣足食!Python3网络爬虫实战案例
  2. HTML5 技术在风电、光伏等新能源领域的应用
  3. 计算机网络总结:第二章 应用层
  4. PHP基础系列之正则表达式(一)
  5. php 上传pdf文件损坏,php – 强制下载PDF文件,损坏文件
  6. PHP中没用的验证码
  7. linux下安装node.js
  8. 百万年薪的腾讯员工买得起深圳房子吗?
  9. sql server注入_SQL注入:SQL Server中的介绍和预防方法
  10. Linux之df命令
  11. 舒尔特表-计时开始-暂停-继续 js
  12. 批量导出Outlook所有联系人到vcard文件
  13. servlet登录验证并返回错误信息
  14. 【ES】一、ES入门及JavaAPI使用
  15. 蓝桥杯—交换瓶子—Java
  16. c++面试经验(可下载文档)
  17. Redis(十九),老男孩linux视频
  18. 涛思数据TDengine启动报错,提示localEp is different from localhost.localdomain:6030
  19. 教你如何把精彩的DVD影片拷贝到硬盘上看
  20. 15种顶级分析思维模型,真的顶!

热门文章

  1. 阿里技术嘉年华-aDev内容感悟
  2. Android 拍照是开启(调用)闪光灯(原创)
  3. linux内核__force,Linux内核学习:I2C_SLAVE_FORCE
  4. eeprom stm8l 擦除 读写_STM8L探索套件学习笔记-EEPROM(十一)
  5. 企业为什么要开通银企直联_为什么要开通小红书企业号?——山东同乐电商培训基地...
  6. ad 卡尔曼_对Kalman(卡尔曼)滤波器的理解
  7. 【整理】ABAP 7.40新特性介绍(上)
  8. 【PP生产订单】入门介绍(五)
  9. 动态隐藏ALV的行和列
  10. SAP HR模块用的表