从零开始的JSON教程学习

此文为学习知乎上Milo的编程”专栏所载的从零开始的JSON教程所作的学习笔记,同时也是学习简书的Markdown语法的时间,因为一直想找一个能做学习笔记的网站,并且由于笔记的很多内容涉及代码块,支持Markdown语法的简书似乎是个不错的选择。同时希望自己能够坚持,持续学习。(由于是学习笔记,大量的内容来自于专栏,专栏作者为Milo Yip,特此说明)

一、启程

1. JSON是什么?

JSON是一种用于数据交换的文本格式,具有类似功能的语言有XML、YAML等等,但JSON的语法最简单。一个简单的例子的JSON文本的例子:

 {
    "title": "Design Patterns",
    "subtitle": "Elements of Reusable Object-Oriented Software",
    "author": [
        "Erich Gamma",
        "Richard Helm",
        "Ralph Johnson",
        "John Vlissides"
    ],
    "year": 2009,
    "weight": 1.8,
    "hardcover": true,
    "publisher": {
        "Company": "Pearson Education",
        "Country": "India"
    },
    "website": null
}

由此可以看见,一个JSON对象的表示是用{...},JSON的数据类型有六种数据类型:

Type Format
null null
booleab true or false
number 浮点数
string "Design Patterns"
array [...]
objecte {}

可以发现一个object的数据类型可以是另一个object,这说明JSON是一种树状的结构。一个JSON库应当提供的功能包括:

  • parse:将JSON文本(即JSON字符串)解析为对象,肯定是一个树状的对象
  • stringify:将一个对象文本化,即把一个对象表示为一串JSON文本
  • access:提供方法使得程序中可以访问已经parse过的对象的数据结构

(事实上,对于access不是特别能理解,希望在感悟下)

2. 编译环境配置

pass
此处的内容之后再补充,对于编译环境的搭建CMake、Git的使用还是要抽时间本地使用下

3.头文件与API设计
  • 头文件#include 防范:为了防止重复引用头文件而采取的一种方法,一般为每个头文件中预定义一个唯一的宏,然后判断是否这个宏已经定义过了。
#ifndef LEPTJSON_H__
#define LEPTJSON_H__
/* 此处写入头文件内容,如各种声明 */
#endif /*LEPTJSON_H__*/

一般以_H__作为后缀,并且要保证唯一。

  • 六种数据类型:将truefalse算作两种类型,那么共有其中类型,定义一个enum类型。为了方便使用,用关键字typedef在处理下:
typedef enum { 
        LEPT_NULL, 
        LEPT_FALSE,  
        LEPT_TRUE,
        LEPT_NUMBER, 
        LEPT_STRING,
        LEPT_ARRAY, 
        LEPT_OBJECT
}  lept_type;

一些作者提到的注意点:C语言没有明明空间的概念,因此需要保证标识符的唯一性,因此一般用项目名称的简写做前缀,枚举值用大写而函数和类型定义用小写

  • JSON是一个树状的数据结构,每个结点用一个结构表示,当前第一节只考虑三种类型nullfalsetrue,因此就当前来讲,这个结构只需要存储一个数据类型即可,以下是定义:
typedef struct {
lept_type type;
} lept_value;
  • API定义:
typedef enum {
         LEPT_PARSE_OK , 
         LEPT_PARSE_EXPECT_VALUE,
         LEPT_PARSE_INVALID_VALUE,
         LEPT_PARSE_ROOT_NOT_SINGULAR
} lept_parse_result;      
/*API-1,解析一个json,即parse,结果填入一个lept_value。注意const的用法是保证json不会被改动*/
lept_parse_result lept_parse(lept_value &v, const char* json);       
/*API-2,获取结果,即access,注意const 以及指针的使用(防止对象拷贝)*/
lept_type lept_get_tyepe(const lept_value* v);
  • 此单元json只包含null,false,true三种类型,语法描述为:
json_text = ws value ws
ws = *(%0x20, %x0x09, %0x0A, %x0D)   ------*  表示零或多个
value = 'null' / 'false' / 'true'    -----/ 表示其中一个

前面已经提到了lept_parse的返回类型,下面表示本单元语法下分别代表的含义:

typedef enum {
         LEPT_PARSE_OK ,         //解析成功
         LEPT_PARSE_EXPECT_VALUE,  //JSON串只有空白
         LEPT_PARSE_INVALID_VALUE,
         LEPT_PARSE_ROOT_NOT_SINGULAR //一个值、空白后还有其他值
} lept_parse_result;    
  • TTD(测试驱动开发)
    是一种开发方法,主要是:
    1. 加入一个测试
    2. 运行所有测试,新的测试会失败
    3. 编写实现代码
    4. 运行所有测试,如有失败返回3
    • 重构代码,并测试,如有失败返回3
    • 返回1

TTD是先写测试在写开发,优点是实现刚好满足测试的代码,且容易把控质量。本项目提供了一个测试框架。以下做代码学习。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "leptjson.h"

static int main_ret = 0;
static int test_count = 0;
static int test_pass = 0;
//注意宏分多行写的技巧 
//注意fprintf和printf区别:注意format为什么可以这么写:类似于char * = “%d”“%d”这样写没毛病,注意stderr
//printf是向stdout,fprintf是向FILE*输出,stderr和stdout等都是该类型,
//stderr时另一个输
//出流
#define EXPECT_EQ_BASE(equality, expect, actual, format) \
    do {\
        test_count++;\
        if (equality)\
            test_pass++;\
        else {\
            fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", __FILE__, __LINE__, expect, actual);\
            main_ret = 1;\
        }\
    } while(0)

#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d")

static void test_parse_null() {
    lept_value v;
    v.type = LEPT_TRUE;
    EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "null"));
    EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v));
}

/* ... */

static void test_parse() {
    test_parse_null();
    /* ... */
}

int main() {
    test_parse();
    printf("%d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count);
    return main_ret;
}
4. 课后习题

其他的就不关注 了,有一点有意思的要注意下,当有一个函数申明为static后意味这个函数只在当前编译单元使用

一、启程

1. JSON是什么?
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容