cJSON源码分析(三)
作者:互联网
在构建好一个JSON对象之后,如何访问呢?
首先试着将json字符串序列化,并全部打印出来看下结构再说:
char * string = "{\"name\":\"xxx\", \"name2\":\"xxx2\"}";cJSON * root = cJSON_Parse(string);//json字符串序列化printf("%s\n", cJSON_Print(root));//json格式化输出
看源码了解一下cJSON_Print函数大致实现过程吧(cJSON_Parse函数实现的源码可翻阅前面文章)
/* printbuffer结构体主要用作格式化或非格式化打印json数据结构的缓冲区 */typedef struct{ unsigned char *buffer; //内容 size_t length; //长度 size_t offset; //偏移量 size_t depth; /* current nesting depth (for formatted printing) 当前嵌套深度(用于格式化打印)*/ cJSON_bool noalloc; //bool类型 cJSON_bool format; /*bool类型, is this print a formatted print 这是是否格式化输出,用true,false控制*/ internal_hooks hooks; //通过hook对内存进行操作} printbuffer;#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) //判断大小,全部用括号括起来,否则如果a,b是表达式且含有比<符号级别更低的运算符就会出现不可预料的错误/* Render a cJSON item/entity/structure to text. 将项目/实体/结构呈现为文本*/CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item){ return (char*)print(item, true, &global_hooks);//global_hooks作为全局变量负责分配内存缓冲区}static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks){ static const size_t default_buffer_size = 256; printbuffer buffer[1]; unsigned char *printed = NULL; memset(buffer, 0, sizeof(buffer)); /* create buffer 创建缓冲区读取字符*/ buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); buffer->length = default_buffer_size; buffer->format = format; buffer->hooks = *hooks; if (buffer->buffer == NULL) { goto fail; } /* print the value */ if (!print_value(item, buffer)) { goto fail; } update_offset(buffer);//更新偏移量 /* check if reallocate is available */ if (hooks->reallocate != NULL)//检查开辟的空间是否满足 { printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);//动态增加或减少空间 if (printed == NULL) { goto fail; } buffer->buffer = NULL; } else /* otherwise copy the JSON over to a new buffer 否则,将JSON复制到新的缓冲区*/ { printed = (unsigned char*) hooks->allocate(buffer->offset + 1); if (printed == NULL) { goto fail; } memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); printed[buffer->offset] = '\0'; /* just to be sure 只是想确定一下,应该是保证字符串有正确的结束符号*/ /* free the buffer */ hooks->deallocate(buffer->buffer);//释放缓冲区内存 } return printed;fail: if (buffer->buffer != NULL) { hooks->deallocate(buffer->buffer); } if (printed != NULL) { hooks->deallocate(printed); } return NULL;}/* Render a value to text. 将值呈现为文本。*/static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer){ unsigned char *output = NULL; if ((item == NULL) || (output_buffer == NULL)) { return false; } switch ((item->type) & 0xFF)//0xFF, 表示item->type取低8位的值作为参数,更高位的数据不参考 { case cJSON_NULL: output = ensure(output_buffer, 5);//确保偏移量足够容纳内容 if (output == NULL) { return false; } strcpy((char*)output, "null"); return true; case cJSON_False: output = ensure(output_buffer, 6); if (output == NULL) { return false; } strcpy((char*)output, "false"); return true; case cJSON_True: output = ensure(output_buffer, 5); if (output == NULL) { return false; } strcpy((char*)output, "true"); return true; case cJSON_Number: return print_number(item, output_buffer); case cJSON_Raw: { size_t raw_length = 0; if (item->valuestring == NULL) { return false; } raw_length = strlen(item->valuestring) + sizeof(""); output = ensure(output_buffer, raw_length); if (output == NULL) { return false; } memcpy(output, item->valuestring, raw_length); return true; } case cJSON_String: return print_string(item, output_buffer); case cJSON_Array: return print_array(item, output_buffer); case cJSON_Object: return print_object(item, output_buffer); default: return false; }}/* calculate the new length of the string in a printbuffer and update the offset 计算打印缓冲区中字符串的新长度并更新偏移量*/static void update_offset(printbuffer * const buffer){ const unsigned char *buffer_pointer = NULL; if ((buffer == NULL) || (buffer->buffer == NULL)) { return; } buffer_pointer = buffer->buffer + buffer->offset; buffer->offset += strlen((const char*)buffer_pointer);}/* realloc printbuffer if necessary to have at least "needed" bytes more 重新分配printbuffer(如果需要的话)至少“需要”更多的字节*/static unsigned char* ensure(printbuffer * const p, size_t needed){ unsigned char *newbuffer = NULL; size_t newsize = 0; if ((p == NULL) || (p->buffer == NULL)) { return NULL; } if ((p->length > 0) && (p->offset >= p->length)) { /* make sure that offset is valid 确保偏移量有效*/ return NULL; } if (needed > INT_MAX) { /* sizes bigger than INT_MAX are currently not supported 当前不支持大于INT_MAX的大小*/ return NULL; } needed += p->offset + 1; if (needed <= p->length) { return p->buffer + p->offset; } if (p->noalloc) { return NULL; } /* calculate new buffer size 计算新缓冲区大小*/ if (needed > (INT_MAX / 2)) { /* overflow of int, use INT_MAX if possible int会溢出,溢出原因我认为是当int数是负数的时候,符号位为1,运算之后可能会超出size_t的大小 如果可能,请使用 INT_MAX*/ if (needed <= INT_MAX) { newsize = INT_MAX; } else { return NULL; } } else { newsize = needed * 2; } if (p->hooks.reallocate != NULL) { /* reallocate with realloc if available 重新分配与重新分配(如果可用)*/ newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); if (newbuffer == NULL) { p->hooks.deallocate(p->buffer); p->length = 0; p->buffer = NULL; return NULL; } } else { /* otherwise reallocate manually 否则手动重新分配*/ newbuffer = (unsigned char*)p->hooks.allocate(newsize); if (!newbuffer) { p->hooks.deallocate(p->buffer); p->length = 0; p->buffer = NULL; return NULL; } memcpy(newbuffer, p->buffer, p->offset + 1); p->hooks.deallocate(p->buffer); } p->length = newsize; p->buffer = newbuffer; return newbuffer + p->offset;}
序列化json字符串确实繁琐,其主要花费时间在缓冲区边界界定,内容复制,内存分配处理上。
大致了解一下工作流程,函数调用顺序大致如下(主要功能):
cJSON_Print ==> print ==> print_value ==>ensure和print_string和print_array等
标签:分析,return,cJSON,hooks,buffer,源码,output,NULL 来源: https://blog.51cto.com/u_14175378/2759886