1. 程式人生 > 其它 >cJSON原始碼分析(三)

cJSON原始碼分析(三)

技術標籤:C++

在構建好一個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等