日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

cJSON库源码分析

發布時間:2025/6/15 javascript 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 cJSON库源码分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

cJSON是一個超輕巧,攜帶方便,單文件,簡單的可以作為ANSI-C標準的Json格式解析庫。

? ? ? ???那什么是Json格式?這里照搬度娘百科的說法:

? ? ? ???Json(JavaScript Object Notation) 是一種輕量級的數據交換格式。它基于JavaScript(Standard ECMA-262 3rd Edition – December 1999)的一個子集。JSON采用完全獨立于語言的文本格式,但是也使用了類似于C語言家族的習慣(包括C, C++, C#, Java, JavaScript, Perl, Python等)。這些特性使JSON成為理想的數據交換語言。易于人閱讀和編寫,同時也易于機器解析和生成。

? ? ? ???更加詳細的解釋和示例請查看?http://www.json.org/?主頁。

? ? ? ???其實簡單說,Json就是一種信息交換格式,而cJSON其實就是對Json格式的字符串進行構建和解析的一個C語言函數庫。

? ? ? ???可以在以下地址下載到cJSON的源代碼:

? ? ? ???http://sourceforge.net/projects/cjson/

? ? ? ???__MACOSX目錄是提供給Mac OS的源碼,我的機器運行的是Fedora 18,所以選擇另外一個目錄即可。

? ? ? ???簡單的閱讀下README文件,先學習cJSON庫的使用方法。若是連庫都還不會使用,分析源碼就無從談起了。通過簡單的了解,我們得知cJSON庫實際上只有cJSON.c和cJSON.h兩個文件組成,絕對輕量級。

? ? ? ???不過,代碼風格貌似有點非主流,先用indent格式化一下代碼吧。我個人喜歡K&R風格的代碼,使用的indent命令行參數如下:

1

indent?-?bad?-?bli?0?-?ce?-?kr?-?nsob?--?space?-?after?-?if?--?space?-?after?-?while?--?space?-after?-?for?--?use?-?tabs?-?i8

? ? ? ???格式化之后,代碼結構看起來清晰多了。

? ? ? ???那么,從何處下手來分析呢?打開代碼文件逐行閱讀么?當然不是了,有main函數的程序大都是從main函數開始分析,那么沒有main函數的純函數庫呢?那就自己寫main函數唄。

? ? ? ???cJSON作為Json格式的解析庫,其主要功能無非就是構建和解析Json格式了,我們先寫一個構建Json格式字符串的程序,盡可能的使其用到的類型多一點(事實上README文件里提供了不錯的示例代碼,我們直接借鑒一下吧)。代碼如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

#include <stdio.h>

#include <stdlib.h>

#include "cJSON.h"

int?main?(?int?argc?,?char?*?argv?[?]?)

{

?????cJSON?*?root?,?*?fmt?;

?????root?=?cJSON_CreateObject?(?)?;

?????cJSON_AddStringToObject?(?root?,?"name"?,?"Jack (\"Bee\") Nimble"?)?;

?????fmt?=?cJSON_CreateObject?(?)?;

?????cJSON_AddItemToObject?(?root?,?"format"?,?fmt?)?;

?????cJSON_AddStringToObject?(?fmt?,?"type"?,?"rect"?)?;

?????cJSON_AddNumberToObject?(?fmt?,?"width"?,?1920?)?;

?????cJSON_AddFalseToObject?(?fmt?,?"interlace"?)?;

?????char?*?result?=?cJSON_Print?(?root?)?;

?????puts?(?result?)?;

?????free?(?result?)?;

?????cJSON_Delete?(?root?)?;

?????return?EXIT_SUCCESS?;

}

? ? ? ??編譯運行后?(?編譯時注意要鏈接數學庫,參數行要加?-lm)?,運行結果如下:

12345678{

?????"name"?:?"Jack (\"Bee\") Nimble"?,

"format"?:?{

?????????"type"?:?"rect"?,

?????????"width"?:?1920?,

?????????"interlace"?:?false

}}

? ? ? ? 打開cJSON.h這個頭文件,我們可以看到每一個節點,實際上都是由cJSON這個結構體來描述的:

1 2 3 4 5 6 7 8 9 10 11 12

typedef?struct?cJSON?{

?????struct?cJSON?*?next?,?*?prev?;

?????struct?cJSON?*?child?;

int?type?;

?????char?*?valuestring?;

?????int?valueint?;

?????double?valuedouble?;

?????char?*?string?;

}?cJSON?;

? ? ? ??結合這個結構體和上面相關API的調用,其實我們大概可以猜測出cJSON對于Json格式的描述和處理的方法了:

? ? ? ???每一個cJSON結構都描述了一項”鍵-值”對的數據,其中next和prev指針顯然是指向同級前后的cJSON結構,而child指針自然是指向孩子節點的cJSON結構。type類型顯然是為了區分值的類型而設置的,在cJSON.h文件一開始就定義了這些類型的值:

12345678

/* cJSON Types: */

#define cJSON_False??0

#define cJSON_True?? 1

#define cJSON_NULL?? 2

#define cJSON_Number 3

#define cJSON_String 4

#define cJSON_Array??5

#define cJSON_Object 6

? ? ? ??很顯然通過檢測這里的type字段,就很容易知道該節點的類型以及其實際存儲數據的字段了。其它的字段是什么意思呢?cJSON.h文件里的注釋說的很明白了,valueint,valuedouble以及valuestring保存的是相應的值,string存放的是本字段的名字。

? ? ? ???接下來分析程序的執行過程,編譯參數加上-g,使用gdb調試程序,畫出整個構造過程的函數調用圖。具體的調試過程就不細說了,我撿一些關鍵點說說:

? ? ? ? 調試過程中,我們發現?cJSON_AddStringToObject()?等其實是宏定義,本質上調用的都是?cJSON_AddItemToObject()?函數,在cJSON.h文件中可以看到如下定義:

1 2 3 4 5 6

#define cJSON_AddNullToObject(object,name)??????cJSON_AddItemToObject(object, name, cJSON_CreateNull())

#define cJSON_AddTrueToObject(object,name)??????cJSON_AddItemToObject(object, name, cJSON_CreateTrue())

#define cJSON_AddFalseToObject(object,name)???? cJSON_AddItemToObject(object, name, cJSON_CreateFalse())

#define cJSON_AddBoolToObject(object,name,b)????cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))

#define cJSON_AddNumberToObject(object,name,n)??cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))

#define cJSON_AddStringToObject(object,name,s)??cJSON_AddItemToObject(object, name, cJSON_CreateString(s))

? ? ? ? 另外?cJSON_CreateNull()?等函數都是調用?cJSON_New_Item()?函數申請到初始化為0的空間構造相關的節點信息。構造過程中的函數調用圖如下:


? ? ? ???構造的Json字符串最終在內存中形成的結構如下圖所示:

? ? ? ? 構造過程相對來說比較簡單,數組類型這里沒有涉及到,但是分析起來也很簡單。

? ? ? ???我們最后調用?cJSON_Print()?函數生成這個結構所對應的字符串。生成說起來容易,遍歷起整個結構并進行字符串格式控制卻比較繁瑣。這里相關的代碼還有遞歸清理這個內存結構的函數不再贅述,有興趣的同學請自行研究。

? ? ? ???構造的過程我們就說到這里,明天我們研究下解析的過程。


? ? ? ???昨天簡單的分析了一下cJSON對Json格式的構造過程,今天仔細讀了讀README文件,發現README其實說的已經很詳細了。重復造輪子就重復造輪子吧,今天我們再一起分析解析的過程。

? ? ? ???繼續用之前構造的Json格式來進行解析,之前分析構造函數的時候,我們只是簡單的分析了幾個cJSON結構的構造過程,并沒有涉及到各種類型的數組等構造。因為我覺得理解了一般的構造過程,更復雜的類型自己再簡單看看源碼,畫畫圖就很容易理解。

? ? ? ????學習一個事物一定要先抓住主線,先掌握一個事物最常用的那50%,其他的邊邊角角完全可以留給實踐去零敲碎打(孟巖語)。

閑話打住,先上一段解析使用的代碼:

12345678910111213141516171819202122232425262728293031

#include <stdio.h>

#include <stdlib.h>

#include "cJSON.h"

int?main?(?int?argc?,?char?*?argv?[?]?)

{

char?*?text?=?"{\"name\": \"Jack (\\\"Bee\\\") Nimble\", "

?????????????????????????"\"format\": {\"type\": \"rect\", "

?????????????????????????"\"width\": 1920, \"interlace\": false}}"?;

cJSON?*?root?=?cJSON_Parse?(?text?)?;

if?(?!?root?)?{

printf?(?"Error before: [%s]\n"?,?cJSON_GetErrorPtr?(?)?)?;

return?EXIT_FAILURE?;

}

char?*?out?=?cJSON_Print?(?root?)?;

printf?(?"text:\n%s\n\n"?,?out?)?;

free?(?out?)?;

char?*?name?=?cJSON_GetObjectItem?(?root?,?"name"?)?->?valuestring?;

printf?(?"name : %s\n"?,?name?)?;

cJSON?*?format?=?cJSON_GetObjectItem?(?root?,?"format"?)?;

int?width?=?cJSON_GetObjectItem?(?format?,?"width"?)?->?valueint?;

printf?(?"width : %d\n"?,?width?)?;

cJSON_Delete?(?root?)?;

return?EXIT_SUCCESS?;

}

? ? ? ???程序運行輸出:

1 2 3 4 5 6 7 8 9 10 11 12 text?: {

"name"?:?"Jack (\"Bee\") Nimble"?,

"format"?:?{ "type"?:?"rect"?, "width"?:?1920?,

"interlace"?:?false

} }

name?:?Jack?(?"Bee"?)?Nimble

width?:?1920

? ? ? ???從這段代碼中可以看到,解析過程就?cJSON_Parse()?一個接口,調用成功返回cJSON結構體的指針,錯誤返回NULL,此時調用?cJSON_GetErrorPtr()?可以得要錯誤原因的描述字符串。

? ? ? ???查看?cJSON_GetErrorPtr()?的源碼可以得知,其實錯誤信息就保存在全局字符串指針ep里。

? ? ? ???關鍵就是對?cJSON_Parse()?過程的分析了,我們帶參數-g重新編譯代碼并下斷點開始調試跟蹤。

? ? ? ???首先?cJSON_Parse()?調用?cJSON_New_Item()?申請一個新的cJSON節點,然后使用函數對輸入字符串進行解析(中間使用了?skip()?函數來跳過空格和換行符等字符)。

? ? ? ???parse_value()?函數對輸入字符串進行匹配和解析,檢測輸入數據的類型并調用?parse_string()?、?parse_number()?、?parse_array()?、?parse_object()?等函數進行解析,然后返回結束的位置。

? ? ? ???函數調用的關系如下圖:


? ? ? ???這些函數之間相互調用,傳遞待解析的字符串直到結束或者遇見錯誤便返回,最后會構建出一個和之前結構一樣的Json內存結構來,解析的過程就完成了。檢索過程很簡單?cJSON_GetObjectItem()?函數負責進行某個對象的自成員的名字比對和指針的返回。不過要注意這里采用了?cJSON_strcasecmp()?這個無視大小寫的字符串比較函數,因為Json格式的鍵值對的名稱不區分大小寫。

? ? ? ? 這樣cJSON庫的整個構建和解析過程的主干內容就總結出來了,剩下的邊邊角角可以在這個主線分析結束之后再繼續下去,比如Json格式化,解析出來的內存結構復制,從這個內存結構解析出字符串以及這個內存結構的遞歸刪除等等留給大家自己進行吧。

? ? ? ???P.S.?cJSON_InitHooks()?這個函數不過是cJSON允許用戶使用其它的內存申請和釋放函數罷了(默認是malloc和free),另外啰嗦一下,這個接口也可以用來檢測內存泄露。只要實現malloc和free的包裝函數,在其中統計和打印內存申請釋放操作就可以了。

總結

以上是生活随笔為你收集整理的cJSON库源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 天天干天天爱天天射 | 裸体一区二区三区 | 少妇高潮一区二区三区99小说 | 日本黄视频在线观看 | 欧美视频免费看欧美视频 | 女性裸体视频网站 | 色欲久久久天天天精品综合网 | 亚洲情涩 | 一区二区三区欧美视频 | 国产亚洲无码精品 | 日韩二级片 | 久章草影院 | 青娱乐精品视频 | 色爱AV综合网国产精品 | 亚洲色视频 | 亚洲蜜桃精久久久久久久久久久久 | 九九五月天 | 午夜久久网站 | 99热麻豆| 色倩网站 | 尤物视频一区 | 亚洲8888 | 午夜av免费在线观看 | 粉嫩一区二区三区 | 国产在线观看一区二区三区 | 三级全黄的视频 | 日韩一区二区不卡视频 | 国产精品国产三级国产专区53 | 久久综合福利 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 日日夜夜天天操 | 青青视频免费观看 | 国产精品伦一区 | 在线看片日韩 | 狠狠撸视频 | 日韩欧美一区二 | 国产毛毛片 | 性网址| 香蕉视频亚洲 | 日韩精品免费在线 | www.三区| wwwav视频在线观看 | 六月激情婷婷 | 波多野结衣一二三四区 | av自拍偷拍| 91九色porny视频 | 69sex久久精品国产麻豆 | 亚洲日本色图 | 国产精品久久久久影院 | 四虎精品视频 | 久久精品久久久精品美女 | 福利片av| 女生隐私免费看 | 亚洲性在线 | 亚洲区一区二 | 精品一卡二卡 | 91福利视频免费观看 | 国产亚洲精品熟女国产成人 | 欧美亚洲精品在线 | 男人操女人免费视频 | 久久一卡二卡 | 热久久国产精品 | 亚洲色成人一区二区三区小说 | 色哟哟网站入口 | 国精品无码人妻一区二区三区 | 奇米第四色777 | 成人免费播放视频 | 波多野结衣一本一道 | 好色成人网| 精品一区二区三区毛片 | 国产又粗又黄又爽的视频 | 国产成人无码一区二区三区在线 | 色视频免费在线观看 | 国产新婚疯狂做爰视频 | 国产免费91| 91久久精品国产91性色tv | 精品国产乱码久久久久久图片 | kendra lust free xxx | 国模无码大尺度一区二区三区 | 久久国产精品波多野结衣av | 免费三片60分钟 | 操操操av | 国产日韩欧美日韩大片 | 激情久久中文字幕 | 久久久久久久久久久久久久 | 婷婷亚洲五月色综合 | 啪啪免费 | 欧美有码视频 | 性欧美极品另类 | 亚洲国产日韩欧美在线观看 | 中文字幕在线第一页 | 久草在在线视频 | 成人特级毛片 | 50度灰在线| 天天爽网站 | 91www| 久久国产精品久久久久久 | 亚洲第一成人av | a资源在线|