在构建好一个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等