cJSON学习笔记
安装
https://github.com/DaveGamble/cJSON
组包
#include <stdio.h>
#include "cJSON.h"
int main(){
// 创建dict结点
cJSON *root = cJSON_CreateObject();
// 添加string子节点
cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
// 添加number子节点
cJSON_AddItemToObject(root, "age", cJSON_CreateNumber(20));
// 添加bool子节点
cJSON_AddItemToObject(root, "best", cJSON_CreateBool(cJSON_True));
// 添加bool子节点
cJSON_AddItemToObject(root, "worse", cJSON_CreateFalse());
// 添加NULL子节点
cJSON_AddItemToObject(root, "address", cJSON_CreateNull());
// 添加array
cJSON *string_array = cJSON_CreateArray();
cJSON_AddItemToObject(string_array,"hello",cJSON_CreateString("hello"));
cJSON_AddItemToObject(string_array,"world",cJSON_CreateString("world"));
cJSON_AddItemToObject(root,"string",string_array);
// 添加array
int nums[] = {1,2,3,4,5,6};
cJSON *nums_array = cJSON_CreateIntArray(nums,sizeof(nums)/sizeof(int));
cJSON_AddItemToObject(root,"nums",nums_array);
// 格式化输出, 调用malloc
printf("%s\n",cJSON_Print(root));
// 非格式化输出, 调用malloc
printf("%s\n",cJSON_PrintUnformatted(root));
// 不调用malloc
char buffer[4096] = {0};
cJSON_PrintPreallocated(root,buffer,sizeof(buffer),0);//0 非格式化, 1格式化
printf("%s\n",buffer);
// 删除节点, 如果直接调用cJSON_Delete删除某个节点, print的时候会出错的
cJSON_DeleteItemFromObjectCaseSensitive(root,"age");// 大小写敏感
// cJSON_DeleteItemFromObject// 大小写不敏感
// 更新节点
cJSON_ReplaceItemInObjectCaseSensitive(root,"name",cJSON_CreateString("小明"));// 大小写敏感
// cJSON_ReplaceItemInObject// 大小写不敏感
// 格式化输出, 调用malloc
printf("%s\n",cJSON_Print(root));
// 删除根节点
cJSON_Delete(root);
}
解包
#include <stdio.h>
#include "cJSON.h"
int main(){
char s[] = "{\"name\":\"Jack (\\\"Bee\\\") Nimble\",\"age\":20,\"best\":true,\"worse\":false,\"address\":null,\"string\":[\"hello\",\"world\"],\"nums\":[1,2,3,4,5,6]}";
cJSON *root, *object, *sub_object;
// 解析
root = cJSON_Parse(s);
// 字符串
object = cJSON_GetObjectItemCaseSensitive(root,"name");
printf("%d %s\n",cJSON_IsString(object), cJSON_GetStringValue(object));
object = cJSON_GetObjectItem(root,"NAME");
printf("%d %s\n",cJSON_IsString(object), cJSON_GetStringValue(object));
// 数字
object = cJSON_GetObjectItemCaseSensitive(root,"age");
printf("%d %lf\n",cJSON_IsNumber(object), cJSON_GetNumberValue(object));
// 数组
object = cJSON_GetObjectItemCaseSensitive(root,"string");
printf("%d %d\n",cJSON_IsArray(object), cJSON_GetArraySize(object));
int i,n = cJSON_GetArraySize(object);
for(i=0;i<n;i++){
sub_object = cJSON_GetArrayItem(object,i);
printf("%d %s\n",cJSON_IsString(sub_object), cJSON_GetStringValue(sub_object));
}
// 删除根节点
cJSON_Delete(root);
}
解包与可变参数
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "cJSON.h"
#define get_cjson_string(args...) _get_cjson_string(args,"")
int _get_cjson_string(cJSON * root, char * value, int value_size, ...)
{
va_list ap;
char *key;
cJSON *object;
va_start(ap, value_size);
for(key=va_arg(ap, char*),object=root;key[0]!='\0';key=va_arg(ap, char*)){
object = cJSON_GetObjectItemCaseSensitive(object,key);
if(object == NULL){
printf("no find %s\n",key);
break;
}
}
va_end(ap);
if(object==NULL || !cJSON_IsString(object)){
return -1;
}
int len = strlen(cJSON_GetStringValue(object));
if(len > value_size){
return -1;
}
strcpy(value,cJSON_GetStringValue(object));
return len;
}
#define get_cjson_number(args...) _get_cjson_number(args,"")
int _get_cjson_number(cJSON * root, double * value, ...){
va_list ap;
char *key;
cJSON *object;
va_start(ap, value);
for(key=va_arg(ap, char*),object=root;key[0]!='\0';key=va_arg(ap, char*)){
object = cJSON_GetObjectItemCaseSensitive(object,key);
if(object == NULL){
printf("no find %s\n",key);
break;
}
}
va_end(ap);
if(object==NULL || !cJSON_IsNumber(object)){
return -1;
}
*value = cJSON_GetNumberValue(object);
return 0;
}
#define get_cjson_object(args...) _get_cjson_object(args,"")
cJSON * _get_cjson_object(cJSON * root, ...){
va_list ap;
char *key;
cJSON *object;
va_start(ap, root);
for(key=va_arg(ap, char*),object=root;key[0]!='\0';key=va_arg(ap, char*)){
object = cJSON_GetObjectItemCaseSensitive(object,key);
if(object == NULL){
printf("no find %s\n",key);
break;
}
}
va_end(ap);
return object;
}
int main(){
char s[] = "{\"name\":\"Jack (\\\"Bee\\\") Nimble\",\"age\":20,\"best\":true,\"worse\":false,\"address\":null,\"string\":[\"hello\",\"world\"],\"nums\":[1,2,3,4,5,6]}";
cJSON *root, *object, *sub_object;
// 解析
root = cJSON_Parse(s);
// 字符串
char tmp[1024] = {0};
get_cjson_string(root,tmp,sizeof(tmp)-1,"name");
printf("%s\n",tmp);
// 数字
double f = 0.0;
get_cjson_number(root,&f,"age");
printf("%lf\n",f);
// 删除根节点
cJSON_Delete(root);
}
优化
重定义malloc和free, 可以优化组包解包速度
因为绝大部分场景,基本都是调用malloc生成新节点,然后在最后delete根节点的时候一起free释放所有节点。所以可以预先在堆中定义一个大buffer, malloc则从buffer中申请
#include <stdio.h>
#include "cJSON.h"
int main(int argc,char** argv){
unsigned char buff[8192],*p = buff;
void *my_malloc(size_t sz){
if(sizeof(buff) - (p-buff) < sz){
return NULL;
}
unsigned char *p_tmp = p;
p += sz;
return p_tmp;
}
void my_free(void* ptr){
return;
}
cJSON_Hooks hooks = {my_malloc,my_free};
cJSON_InitHooks(&hooks);// 替换原有的malloc和free
cJSON *root,*fmt;
root = cJSON_CreateObject();
cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
cJSON_AddItemToObject(root, "format", fmt = cJSON_CreateObject());
cJSON_AddStringToObject(fmt, "type", "rect");
cJSON_AddNumberToObject(fmt, "width", 1920);
cJSON_AddNumberToObject(fmt, "height", 1080);
cJSON_AddFalseToObject (fmt, "interlace");
cJSON_AddNumberToObject(fmt, "frame rate", 24);
printf("%s\n",cJSON_PrintUnformatted(root));
cJSON_Delete(root);
cJSON_InitHooks(NULL);// 还原为原有的malloc和free
}
测试程序
测试环境:树莓派4B
test_stack.c
#include <stdio.h>
#include "cJSON.h"
int main(int argc,char** argv){
int n = 10000,i;
if(argc > 1){
n = atoi(argv[1]);
}
for(i=0;i<n;i++){
unsigned char buff[8192],*p = buff;
void *my_malloc(size_t sz){
if(sizeof(buff) - (p-buff) < sz){
return NULL;
}
unsigned char *p_tmp = p;
p += sz;
return p_tmp;
}
void my_free(void* ptr){
return;
}
cJSON_Hooks hooks = {my_malloc,my_free};
cJSON_InitHooks(&hooks);
cJSON *root,*fmt;
root = cJSON_CreateObject();
cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
cJSON_AddItemToObject(root, "format", fmt = cJSON_CreateObject());
cJSON_AddStringToObject(fmt, "type", "rect");
cJSON_AddNumberToObject(fmt, "width", 1920);
cJSON_AddNumberToObject(fmt, "height", 1080);
cJSON_AddFalseToObject (fmt, "interlace");
cJSON_AddNumberToObject(fmt, "frame rate", 24);
// printf("%s\n",cJSON_PrintUnformatted(root));
cJSON_Delete(root);
cJSON_InitHooks(NULL);
}
}
test_heap.c
#include <stdio.h>
#include "cJSON.h"
int main(int argc,char** argv){
int n = 10000,i;
if(argc > 1){
n = atoi(argv[1]);
}
for(i=0;i<n;i++){
cJSON *root,*fmt;
root = cJSON_CreateObject();
cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
cJSON_AddItemToObject(root, "format", fmt = cJSON_CreateObject());
cJSON_AddStringToObject(fmt, "type", "rect");
cJSON_AddNumberToObject(fmt, "width", 1920);
cJSON_AddNumberToObject(fmt, "height", 1080);
cJSON_AddFalseToObject (fmt, "interlace");
cJSON_AddNumberToObject(fmt, "frame rate", 24);
// printf("%s\n",cJSON_PrintUnformatted(root));
cJSON_Delete(root);
}
}
Makefile
SRC = $(wildcard *.c)
OBJ = $(patsubst %.c, %.o, $(SRC))
all : test_stack test_heap
test_stack:test_stack.o cJSON.o
gcc -o $@ $^
test_heap:test_heap.o cJSON.o
gcc -o $@ $^
$(OBJ):%.o:%.c
gcc -c -o $@ $< -O3
clean:
-rm $(OBJ) $(all)
.PHONY:all clean
1000000次循环测试结果
> time ./test_stack 1000000
real 0m0.868s
user 0m0.867s
sys 0m0.000s
> time ./test_heap 1000000
real 0m3.093s
user 0m3.093s
sys 0m0.000s
参考:
https://blog.csdn.net/Mark_md/article/details/108548524
https://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap
https://stackoverflow.com/questions/161053/which-is-faster-stack-allocation-or-heap-allocation