最近在物联网项目开发中需要使用到cJSON处理字符串,现就相关详情记录下来方便大家参考以及我以后再次复习,谢谢
cJSON
cJSON是一款以C语言编写的超轻量级的JSON字符串的分析器。
JSON
JSON在这个网站有详细的描述:http://www.json.org/,如需要深入的了解JSON,可以前往进行深入的了解。
https://www.ecma-international.org/publications-and-standards/standards/ecma-404/也对JSON有详细的介绍。
#cJSON使用
有一下几种方法可以使用cJSON:
1.直接copy源文件
由于整个有用的源文件就只有一个c源文件和一个头文件,只需要将cJSON.h 和 cJSON.c复制到你的项目中即可。
2.借助CMake
借助 CMake,cJSON 支持完整的构建系统且支持高于或等于2.8.5版本的CMake。通过这种方式,您可以获得最多的特性和功能。
##cJSON数据结构
/* 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;
上述结构体中的“type”项表示JSON数据的数据类型。
该字段是以位为标志进行存储的,主要有以下类型:
cJSON_Invalid:代表该数据不包含任何数据;
cJSON_False:代表该数值为false值;
cJSON_True:代表该数值为True值;
cJSON_NULL:代表该数据为NULL;
cJSON_Number:代表该数值为数据型,包括整形和浮点数。
cJSON_String:代表该数值为字符串;
cJSON_Array:代表该数值为数组;
cJSON_Object:代表该数值为对象类型;
cJSON_Raw:代表该数值是以0结尾的数组;
cJSON_IsReference:
cJSON_StringIsConst:
以上每个数据类型都可以通过一个函数cJSON_Create…来进行创建,并通过cJSON_Delete函数删除。
注意:使用cJSON_Create…创建数据结构变量之后一定使用cJSON_Delete删除,以避免内存泄露。
解析cJSON
对于zero结束的JSON 字符串,可以使用函数cJSON_Parse来进行分析。
cJSON *json = cJSON_Parse(string);
对于给的JSON字符串,可以使用函数cJSON_ParseWithLength来进行分析。
cJSON *json = cJSON_ParseWithLength(string, buffer_length);
cJSON默认使用的是内存分配器是malloc和free,但是可以在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)
。
打印JSON
可以使用cJSON_Print
来打印JSON数据。
char *string = cJSON_Print(json);
cJSON_Print
将使用空格进行打印以进行格式化。
如果要在不格式化的情况下打印,请使用cJSON_PrintUnformatted
。
如果您对生成的字符串有多大有一个粗略的了解,则可以使用cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
。fmt
是一个布尔值,用于打开和关闭空格格式设置。cJSON_Print
当前使用 256 字节作为其第一个缓冲区大小。一旦打印空间不足,就会分配一个新的缓冲区,并在继续打印之前复制旧的缓冲区。
通过使用cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
,可以完全避免这些动态缓冲区分配。它需要一个缓冲区来指向要打印的指针及其长度。如果达到长度,打印将失败并返回0
。如果成功,则返回1
。请注意,您应该提供比实际需要多 5 个字节,因为 cJSON 在估计提供的内存是否足够时并非 100% 准确。
示例
我们要构建的示例如下:
{
"name": "Awesome 4K",
"resolutions": [
{
"width": 1280,
"height": 720
},
{
"width": 1920,
"height": 1080
},
{
"width": 3840,
"height": 2160
}
]
}
创建和打印的示例代码如下:
//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;
}
创建和打印示例代码2:
//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;
}
cJSON使用注意事项
1、不支持包含'\0'
or \u0000
的字符串;
2、只支持UTF-8编码的字符串;
3、只支持ANSI C (or C89, C90);
4、cJSON 不正式支持除 IEEE754 双精度浮点数以外的任何“双精度”实现。它可能仍可与其他实现一起使用,但这些实现的 bug 将被视为无效。
cJSON 支持的浮点文本的最大长度当前为 63 个字符。
5、cJSON 不支持嵌套太深的数组和对象,因为这会导致堆栈溢出。为了防止这种情况,cJSON将深度限制为CJSON_NESTING_LIMIT
,默认情况下为1000,但可以在编译时更改。
6、通常,cJSON 不是线程安全的 。但是,在以下情况下它是线程安全的:
6.1 从不使用cJSON_GetErrorPtr
(可以改用“cJSON_ParseWithOpts”的“return_parse_end”参数)
6.2 cJSON_InitHooks
仅在任何线程中使用 cJSON 之前调用过。
6.3 在对 cJSON 函数的所有调用都返回之前,永远不会调用setlocale
。
7、cJSON 刚开始创建时,没有遵循 JSON 标准,也没有区分大写和小写字母。如果您希望获得正确、符合标准的行为,则需要使用CaseSensitive
功能(如果可用)。
8、cJSON 支持解析和打印包含具有相同名称的多个成员的对象的 JSON数据,但是cJSON_GetObjectItemCaseSensitive
将始终仅返回第一个。