的2k17换电脑登陆后,为什么以前nba2k17辉煌生涯存档的存档

  这篇博文和前一篇&C json实战引擎一,实现解析部分设计是相同的,都是采用递归下降分析.
这里扯一点&假如你是学生&推荐一本书&给&大家
  自制编程语言 /link?url=jIFOBNt26ykhnPr2-UaaDc5_I7gZURXdJ15P2iBXwbglXkdz2qT_tqAz4KoFF0rsS2IQbIP-ij2Ar5EMRzMcuq
当然学了上面内容,以后对编译链接设计方面会有很大提高.&但是对于&其它&也没有什么鸟用.
再扯一点&如果想流畅的看完并成功写完上面书中三个案例.&你还需要&看完&市面上关于&C&讲解的所有出名的&有意义的书籍.
编程很简单,勤能补拙,&想提高就会提高.&但成长很难......
  风暴 &
  同样,一开始将最有益,最简单的部分代码拿出来供大家分享.
1.从简单&有益代码来
  开始分析一段&代码,&先展示一下使用的数据结构
struct cjson {
struct cjson *next, *
struct cjson * // type == _CJSON_ARRAY or type == _CJSON_OBJECT 那么 child 就不为空
char * // json内容那块的 key名称
char * // type == _CJSON_STRING, 是一个字符串
// type == _CJSON_NUMBER, 是一个num值, ((int)c-&vd) 转成int 或 bool
//定义cjson_t json类型
typedef struct cjson* cjson_t;
&再展示用的&tstring&结构
#ifndef _STRUCT_TSTRING
#define _STRUCT_TSTRING
//简单字符串结构,并定义文本字符串类型tstring
struct tstring {
//字符串实际保存的内容
//当前字符串大小
//字符池大小
typedef struct
#endif // !_STRUCT_TSTRING
&这些数据结构前面&博文已经对其进行过详细&设计利用分析.
先看一个&double&变成&cjson_t&的算法,&很多细节真的适合&学习尝试用于底层库封装设计中.
// 将item 中值转换成字符串 保存到p中
static char* __print_number(cjson_t item, tstring p)
char* str = NULL;
double d = item-&
int i = (int)d;
if (d == 0) {
str = __ensure(p, 2);
str[0] = '0', str[1] = '\0';
else if ((fabs(d - i)) &= DBL_EPSILON && d &= INT_MAX && d &= INT_MIN) {
str = __ensure(p, 21); //int 值
sprintf(str, &%d&, i);
str = __ensure(p, 64); //double值
if (str) {
double nd = fabs(d); //得到正值开始比较
if(fabs(floor(d) - d) &= DBL_EPSILON && nd & 1.0e60)
sprintf(str, &%.0f&, d);
else if(nd & 1.0e-6 || nd & 1.0e9) //科学计数法
sprintf(str, &%e&, d);
sprintf(str, &%f&, d);
&是不是感觉&很巧妙.&这里&把&int&和&double&都算作&number类型,&出现了&上面算法.&需要导入 #include &float.h&&引用了&DBL_EPSILON&判断是否相等宏阀值.
&其中 __ensure&函数&是一个&协助&tstring&分配内存的一个函数
这里使用 tstring 结构 size 这里表示 字符串总大小,没有变化
* len 表示当前字符串的字符串起始偏移量 即 tstring-&str + tstring-&len 起始的
static char* __ensure(tstring p, int need)
if (!p || !p-&str) {
SL_FATAL(&p:%p need:%p is error!&, p, need);
return NULL;
need += p-&
if (need &= p-&size) //内存够用直接返回结果
return p-&str + p-&
nsize = __pow2gt(need);
if ((nbuf = malloc(nsize*sizeof(char))) == NULL) {
free(p-&str);
p-&size = p-&len = 0;
p-&str = NULL;
SL_FATAL(&malloc nsize = %d error!&, nsize);
return NULL;
//这里复制内容
memcpy(nbuf, p-&str, p-&size);
free(p-&str);
return nbuf + p-&
&这里采用的&SL_FATAL&日志库,&看我前面博文&如何写一个&高效多用户的&日志库,&特别有用,基本上是开发中标配.
还有一个 __pow2gt(x)&函数技巧,&返回&一个比x&的&n&其中n是2的幂,并且是最小的幂.是一种技巧记住就可以了.估计都是那些写汇编的老代码遗留下来的潜规则吧.
性能没的说.&不明白就当有个印象.
1 // 2^n&=x , n是最小的整数
2 static int __pow2gt(int x)
x |= x && 1;
x |= x && 2;
x |= x && 4;
x |= x && 8;
x |= x && 16;
return x + 1;
到这里&这几个函数&就可以代表这整篇文章了.&后面就可以省略了.
1.开始说&cjson&的&构造
  cjson&解析&先认为&所有的都是&一个&value =&&null&or&bool&or&number&or&string&or&array&or&object
其中&array&or&object&需要再特殊处理,因为其中可能包含&value&即&array or object =& value
这样的递归顺序进行的.&这就是传说中的低估下降分析 !!!!&爽不爽 ,&当我还是学生的时候,NB任务告诉我学会了&递归了下降分析就可以找个
不错的工作,&找个不错的对象.&现在只想说&呵呵!!.
  大概像下面调用关系图
递归嵌套.&好像&Linux&之父&也&说过&去它码的递归.
2.展示&cjson&构造用的接口
  这里比较简单,今天只分析&构造部分&接口就一个
// --------------------------------- 下面是 cjson 输出部分的处理代码 -----------------------------------------
这里是将 cjson_t item 转换成字符串内容,需要自己free
: cjson的具体结点
: 返回生成的item的json串内容
extern char* cjson_print(cjson_t item);
值得注意的是&上面接口能够将&item变成&char*,&这个char*是堆上分配的.&需要自己&用完后&free.
3.&展示&cjson&部分代码
  上面接口构造的函数为
#define _INT_CJONSTR
这里是将 cjson_t item 转换成字符串内容,需要自己free
: cjson的具体结点
: 返回生成的item的json串内容
cjson_print(cjson_t item)
if ((!item) || !(p.str = malloc(sizeof(char)*_INT_CJONSTR))) {
SL_FATAL(&item:%p, p.str = malloc is error!&, item);
return NULL;
p.size = _INT_CJONSTR;
p.len = 0;
out = __print_value(item, &p); //从值处理开始, 返回最终结果
if (out == NULL) {
free(p.str);
SL_FATAL(&__print_value item:%p, p:%p is error!&, item, &p);
return NULL;
return realloc(out,strlen(out) + 1); // 体积变小 realloc返回一定成功
核心&是 __print_value&当然设计方面也参照了一点&cJSON内容.&&那我们&继续细说&它
//这里是 递归下降 的函数声明处, 分别是处理值, 数组, object
static char* __print_value(cjson_t item, tstring p);
static char* __print_array(cjson_t item, tstring p);
static char* __print_object(cjson_t item, tstring p);
// 定义实现部分, 内部私有函数 认为 item 和 p都是存在的
static char* __print_value(cjson_t item, tstring p)
char* out = NULL;
switch ((item-&type) & UCHAR_MAX) { // 0xff
case _CJSON_FALSE: if ((out = __ensure(p, 6))) strcpy(out, &false&);
case _CJSON_TRUE: if ((out = __ensure(p, 5))) strcpy(out, &true&);
case _CJSON_NULL: if ((out = __ensure(p, 5))) strcpy(out, &null&);
case _CJSON_NUMBER:
out = __print_number(item, p);
case _CJSON_STRING:
out = __print_string(item-&vs, p);
case _CJSON_ARRAY:
out = __print_array(item, p);
case _CJSON_OBJECT:
out = __print_object(item, p);
有没有感觉&很自然就是这样的.&&上面先声明的 __print_*&系列函数,是为了告诉编译器这个函数地址是什么,方便它能找到&并进入处理.
再展示&其中 __print_object&处理函数,&也很直白
1 // 同样 假定 item 和 p都是存在且不为NULL, 相信这些代码是安全的
2 static char* __print_object(cjson_t item, tstring p)
int i, ncut,
cjson_t child = item-&
// 得到孩子结点的深度
for (ncut = 0; child = child-&child)
if (!ncut) {
char* out = NULL;
if (!(out = __ensure(p, 3)))
strcpy(out, &{}&);
if (!(ptr = __ensure(p, 2)))
return NULL;
*ptr++ = '{';
*ptr -= '\0';
p-&len += 1;
// 根据子结点 处理
for (child = item-& (child); child = child-&next) {
__print_string(child-&key, p);
p-&len = __update(p);
//加入一个冒号
if (!(ptr = __ensure(p, 1)))
return NULL;
*ptr++ = ':';
p-&len += 1;
//继续打印一个值
__print_value(child, p);
p-&len = __update(p);
//结算最后内容
len = child-&next ? 1 : 0;
if ((ptr = __ensure(p, len + 1)) == NULL)
return NULL;
if (child-&next)
*ptr++ = ',';
*ptr = '\0';
if (!(ptr = __ensure(p, 2)))
return NULL;
*ptr++ = '}';
*ptr = '\0';
return p-&str +
先处理key ,后面value&用 __print_value&处理.&到这里&基本思路都有了,其它是靠你自己努力临摹&把键盘敲烂!
完整部分代码如下
&cjson.h /&有些辅助接口没有实现,下一个博文中全部实现
1 #ifndef _H_CJSON
2 #define _H_CJSON
4 // json 中几种数据类型定义 , 对于C而言 最难的是看不见源码,而不是api复杂, 更不是业务复杂
5 #define _CJSON_FALSE
6 #define _CJSON_TRUE
7 #define _CJSON_NULL
8 #define _CJSON_NUMBER
9 #define _CJSON_STRING
10 #define _CJSON_ARRAY
11 #define _CJSON_OBJECT
13 #define _CJSON_ISREF
//set 时候用如果是引用就不释放了
14 #define _CJSON_ISCONST
//set时候用, 如果是const char* 就不释放了
16 struct cjson {
struct cjson *next, *
struct cjson * // type == _CJSON_ARRAY or type == _CJSON_OBJECT 那么 child 就不为空
// json内容那块的 key名称
// type == _CJSON_STRING, 是一个字符串
// type == _CJSON_NUMBER, 是一个num值, ((int)c-&vd) 转成int 或 bool
26 //定义cjson_t json类型
27 typedef struct cjson* cjson_t;
* 这个宏,协助我们得到 int 值 或 bool 值
* item : 待处理的目标cjson_t结点
34 #define cjson_getint(item) \
((int)((item)-&vd))
删除json串内容
: 待释放json_t串内容
41 extern void cjson_delete(cjson_t* pc);
* 对json字符串解析返回解析后的结果
: 待解析的字符串
47 extern cjson_t cjson_parse(const char* jstr);
* 根据 item当前结点的 next 一直寻找到 NULL, 返回个数
*推荐是数组使用
: 待处理的cjson_t数组对象
: 返回这个数组中长度
55 extern int cjson_getlen(cjson_t array);
* 根据索引得到这个数组中对象
: 数组对象
: 查找的索引 必须 [0,cjson_getlen(array)) 范围内
: 返回查找到的当前对象
63 extern cjson_t cjson_getarray(cjson_t array, int idx);
* 根据key得到这个对象 相应位置的值
: 待处理对象中值
: 寻找的key
: 返回 查找 cjson_t 对象
71 extern cjson_t cjson_getobject(cjson_t object, const char* key);
74 // --------------------------------- 下面是 cjson 输出部分的处理代码 -----------------------------------------
这里是将 cjson_t item 转换成字符串内容,需要自己free
: cjson的具体结点
: 返回生成的item的json串内容
81 extern char* cjson_print(cjson_t item);
83 // --------------------------------- 下面是 cjson 输出部分的辅助代码 -----------------------------------------
* 创建一个bool的对象 b==0表示false,否则都是true
: bool 值 最好是 _Bool
: 返回 创建好的json 内容
90 extern cjson_t cjson_newbool(int b);
91 extern cjson_t cjson_newnumber(double vd);
92 extern cjson_t cjson_newstring(const char* vs);
93 extern cjson_t cjson_newarray(void);
94 extern cjson_t cjson_newobject(void);
* 按照类型,创建 对映类型的数组 cjson对象
*目前支持 _CJSON_NULL _CJSON_BOOL/FALSE or TRUE , _CJSON_NUMBER, _CJSON_STRING
: 类型目前支持 上面几种类型
: 数组原始数据
: 数组中元素长度
: 返回创建的数组对象
104 extern cjson_t cjson_newtypearray(int type, const void* array, int len);
* 将 jstr中 不需要解析的字符串都去掉
: 待处理的json串
: 返回压缩后的json串内容
111 extern char* cjson_mini(char* jstr);
将json文件解析成json内容返回
: json串路径
: 返回处理好的cjson_t 内容,失败返回NULL
118 extern cjson_t cjson_dofile(char* jpath);
120 #endif // !_H_CJSON
1 #include &cjson.h&
2 #include &schead.h&
3 #include &sclog.h&
4 #include &tstring.h&
5 #include &float.h&
6 #include &math.h&
8 // 删除cjson
9 static void __cjson_delete(cjson_t c)
while (c) {
next = c-&
//递归删除儿子
if (!(c-&type & _CJSON_ISREF)) {
if (c-&child) //如果不是尾递归,那就先递归
__cjson_delete(c-&child);
if (c-&vs)
free(c-&vs);
else if (!(c-&type & _CJSON_ISCONST) && c-&key)
free(c-&key);
删除json串内容,最近老是受清华的老学生打击, 会起来的......
: 待释放json_t串内容
33 cjson_delete(cjson_t* pc)
if (!pc || !*pc)
__cjson_delete(*pc);
*pc = NULL;
41 //构造一个空 cjson 对象
42 static inline cjson_t __cjson_new(void)
cjson_t c = calloc(1, sizeof(struct cjson));
SL_FATAL(&calloc sizeof struct cjson error!&);
exit(_RT_EM);
52 // 简化的代码段,用宏来简化代码书写 , 16进制处理
53 #define __parse_hex4_code(c, h) \
if (c &= '0' && c &= '9') \
h += c - '0'; \
else if (c &= 'A' && c &= 'F') \
h += 10 + c - 'A'; \
else if (c &= 'a' && c &= 'z') \
h += 10 + c - 'F'; \
63 // 等到unicode char代码
64 static unsigned __parse_hex4(const char* str)
unsigned h = 0;
char c = *
__parse_hex4_code(c, h);
__parse_hex4_code(c, h);
__parse_hex4_code(c, h);
__parse_hex4_code(c, h);
86 // 分析字符串的子函数,
87 static const char* __parse_string(cjson_t item, const char* str)
static unsigned char __marks[] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
const char *
char *nptr, *
unsigned uc,
if (*str != '\&') { // 检查是否是字符串内容
SL_WARNING(&need \\\& str =& %s error!&, str);
return NULL;
for (ptr = str + 1, len = 0; (c = *ptr++) != '\&' && ++len)
if (c == '\\') //跳过转义字符
if (!(out = malloc(len + 1))) {
SL_FATAL(&malloc %d size error!&, len + 1);
return NULL;
// 这里复制拷贝内容
for (ptr = str + 1, nptr = (c = *ptr) != '\&' && ++ptr) {
if (c != '\\') {
// 处理转义字符
switch ((c = *++ptr)) {
case 'b': *nptr++ = '\b';
case 'f': *nptr++ = '\f';
case 'n': *nptr++ = '\n';
case 'r': *nptr++ = '\r';
case 't': *nptr++ = '\t';
case 'u': // 将utf16 =& utf8, 专门的utf处理代码
uc = __parse_hex4(ptr + 1);
ptr += 4;//跳过后面四个字符, unicode
if ((uc &= 0xDC00 && uc &= 0xDFFF) || uc == 0)
/* check for invalid.
if (uc &= 0xD800 && uc &= 0xDBFF)
/* UTF16 surrogate pairs.
if (ptr[1] != '\\' || ptr[2] != 'u')
/* missing second-half of surrogate.
nuc = __parse_hex4(ptr + 3);
if (nuc & 0xDC00 || nuc&0xDFFF)
/* invalid second-half of surrogate.
uc = 0x10000 + (((uc & 0x3FF) && 10) | (nuc & 0x3FF));
if (uc & 0x80)
else if (uc & 0x800)
else if (uc & 0x10000)
switch (len) {
case 4: *--nptr = ((uc | 0x80) & 0xBF); uc &&= 6;
case 3: *--nptr = ((uc | 0x80) & 0xBF); uc &&= 6;
case 2: *--nptr = ((uc | 0x80) & 0xBF); uc &&= 6;
case 1: *--nptr = (uc | __marks[len]);
default: *nptr++ =
*nptr = '\0';
if (c == '\&')
item-&vs =
item-&type = _CJSON_STRING;
166 // 分析数值的子函数,写的可以
167 static const char* __parse_number(cjson_t item, const char* str)
double n = 0.0, ns = 1.0, nd = 0.0; //n把偶才能值, ns表示开始正负, 负为-1, nd 表示小数后面位数
int e = 0, es = 1; //e表示后面指数, es表示 指数的正负,负为-1
if ((c = *str) == '-' || c == '+') {
ns = c == '-' ? -1.0 : 1.0; //正负号检测, 1表示负数
//处理整数部分
for (c = * c &= '0' && c &= '9'; c = *++str)
n = n * 10 + c - '0';
if (c == '.')
for (; (c = *++str) &= '0' && c &= '9'; --nd)
n = n * 10 + c - '0';
// 处理科学计数法
if (c == 'e' || c == 'E') {
if ((c = *++str) == '+') //处理指数部分
else if (c == '-')
es = -1, ++
for (; (c = *str) &= '0' && c &= '9'; ++str)
e = e * 10 + c - '0';
//返回最终结果 number = +/- number.fraction * 10^+/- exponent
n = ns * n * pow(10.0, nd + es * e);
item-&vd =
item-&type = _CJSON_NUMBER;
201 // 跳过不需要处理的字符
202 static const char* __skip(const char* in)
if (in && *in && *in &= 32) {
while ((c = *++in) && c &= 32)
212 // 递归下降分析 需要声明这些函数
213 static const char* __parse_array(cjson_t item, const char* str);
214 static const char* __parse_object(cjson_t item, const char* str);
215 static const char* __parse_value(cjson_t item, const char* value);
217 // 分析数组的子函数, 采用递归下降分析
218 static const char* __parse_array(cjson_t item, const char* str)
if (*str != '[') {
SL_WARNING(&array str error start: %s.&, str);
return NULL;
item-&type = _CJSON_ARRAY;
str = __skip(str + 1);
if (*str == ']') // 低估提前结束
return str + 1;
item-&child = child = __cjson_new();
str = __skip(__parse_value(child, str));
if (!str) {//解析失败 直接返回
SL_WARNING(&array str error e n d one: %s.&, str);
return NULL;
while (*str == ',') {
cjson_t nitem = __cjson_new();
child-&next =
nitem-&prev =
str = __skip(__parse_value(child, __skip(str + 1)));
if (!str) {// 写代码是一件很爽的事
SL_WARNING(&array str error e n d two: %s.&, str);
return NULL;
if (*str != ']') {
SL_WARNING(&array str error e n d: %s.&, str);
return NULL;
return str + 1; // 跳过']'
256 // 分析对象的子函数
257 static const char* __parse_object(cjson_t item, const char* str)
if (*str != '{') {
SL_WARNING(&object str error start: %s.&, str);
return NULL;
item-&type = _CJSON_OBJECT;
str = __skip(str + 1);
if (*str == '}')
return str + 1;
//处理结点, 开始读取一个 key
item-&child = child = __cjson_new();
str = __skip(__parse_string(child, str));
if (!str || *str != ':') {
SL_WARNING(&__skip __parse_string is error : %s!&, str);
return NULL;
child-&key = child-&
child-&vs = NULL;
str = __skip(__parse_value(child, __skip(str + 1)));
if (!str) {
SL_WARNING(&__skip __parse_string is error 2!&);
return NULL;
// 递归解析
while (*str == ',') {
cjson_t nitem = __cjson_new();
child-&next =
nitem-&prev =
str = __skip(__parse_string(child, __skip(str + 1)));
if (!str || *str != ':'){
SL_WARNING(&__parse_string need name or no equal ':' %s.&, str);
return NULL;
child-&key = child-&
child-&vs = NULL;
str = __skip(__parse_value(child, __skip(str+1)));
if (!str) {
SL_WARNING(&__parse_string need item two ':' %s.&, str);
return NULL;
if (*str != '}') {
SL_WARNING(&object str error e n d: %s.&, str);
return NULL;
return str + 1;
314 // 将value 转换塞入 item json值中一部分
315 static const char* __parse_value(cjson_t item, const char* value)
if ((value) && (c = *value)) {
switch (c) {
// n = null, f = false, t = true
case 'n' : return item-&type = _CJSON_NULL, value + 4;
case 'f' : return item-&type = _CJSON_FALSE, value + 5;
case 't' : return item-&type = _CJSON_TRUE, item-&vd = 1.0, value + 4;
case '\&': return __parse_string(item, value);
case '0' : case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
case '+' : case '-': return __parse_number(item, value);
case '[' : return __parse_array(item, value);
case '{' : return __parse_object(item, value);
// 循环到这里是意外 数据
SL_WARNING(&params value = %s!&, value);
return NULL;
337 * 对json字符串解析返回解析后的结果
338 * jstr
: 待解析的字符串
: 返回解析好的字符串内容
341 cjson_t
342 cjson_parse(const char* jstr)
cjson_t c = __cjson_new();
const char*
if (!(end = __parse_value(c, __skip(jstr)))) {
SL_WARNING(&__parse_value params end = %s!&, end);
cjson_delete(&c);
return NULL;
//这里是否检测 返回测试数据
358 * 根据 item当前结点的 next 一直寻找到 NULL, 返回个数
359 *推荐是数组使用
360 * array
: 待处理的cjson_t数组对象
: 返回这个数组中长度
364 cjson_getlen(cjson_t array)
int len = 0;
if (array)
for (array = array-& array = array-&next)
375 * 根据索引得到这个数组中对象
376 * array
: 数组对象
: 查找的索引 必须 [0,cjson_getlen(array)) 范围内
: 返回查找到的当前对象
380 cjson_t
381 cjson_getarray(cjson_t array, int idx)
DEBUG_CODE({
if (!array || idx & 0) {
SL_FATAL(&array:%p, idx=%d params is error!&, array, idx);
return NULL;
for (c = array-& c&&idx & 0; c = c-&next)
398 * 根据key得到这个对象 相应位置的值
399 * object
: 待处理对象中值
: 寻找的key
: 返回 查找 cjson_t 对象
403 cjson_t
404 cjson_getobject(cjson_t object, const char* key)
DEBUG_CODE({
if (!object || !key || !*key) {
SL_FATAL(&object:%p, key=%s params is error!&, object, key);
return NULL;
for (c = object-& c && str_icmp(key, c-&key); c = c-&next)
420 // --------------------------------- 下面是 cjson 输出部分的处理代码 -----------------------------------------
422 // 2^n&=x , n是最小的整数
423 static int __pow2gt(int x)
x |= x && 1;
x |= x && 2;
x |= x && 4;
x |= x && 8;
x |= x && 16;
return x + 1;
这里使用 tstring 结构 size 这里表示 字符串总大小,没有变化
* len 表示当前字符串的字符串起始偏移量 即 tstring-&str + tstring-&len 起始的
438 static char* __ensure(tstring p, int need)
if (!p || !p-&str) {
SL_FATAL(&p:%p need:%p is error!&, p, need);
return NULL;
need += p-&
if (need &= p-&size) //内存够用直接返回结果
return p-&str + p-&
nsize = __pow2gt(need);
if ((nbuf = malloc(nsize*sizeof(char))) == NULL) {
free(p-&str);
p-&size = p-&len = 0;
p-&str = NULL;
SL_FATAL(&malloc nsize = %d error!&, nsize);
return NULL;
//这里复制内容
memcpy(nbuf, p-&str, p-&size);
free(p-&str);
return nbuf + p-&
465 // 这里更新一下 当前字符串, 返回当前字符串的长度
466 inline static int __update(tstring p)
return (!p || !p-&str) ? 0 : p-&len + strlen(p-&str+p-&len);
471 // 将item 中值转换成字符串 保存到p中
472 static char* __print_number(cjson_t item, tstring p)
char* str = NULL;
double d = item-&
int i = (int)d;
if (d == 0) {
str = __ensure(p, 2);
str[0] = '0', str[1] = '\0';
else if ((fabs(d - i)) &= DBL_EPSILON && d &= INT_MAX && d &= INT_MIN) {
str = __ensure(p, 21); //int 值
sprintf(str, &%d&, i);
str = __ensure(p, 64); //double值
if (str) {
double nd = fabs(d); //得到正值开始比较
if(fabs(floor(d) - d) &= DBL_EPSILON && nd & 1.0e60)
sprintf(str, &%.0f&, d);
else if(nd & 1.0e-6 || nd & 1.0e9) //科学计数法
sprintf(str, &%e&, d);
sprintf(str, &%f&, d);
505 // 输出字符串内容
506 static char* __print_string(char* str, tstring p)
const char*
char *nptr, *
int len = 0, flag = 0;
if (!str || !*str) { //最特殊情况,什么都没有 返回NULL
out = __ensure(p, 3);
return NULL;
out[0] = '\&', out[1] = '\&', out[2] = '\0';
for (ptr = (c=*ptr); ++ptr)
flag |= ((c & 0 && c & 32) || c == '\&' || c == '\\');
if (!flag) {
//没有特殊字符直接处理结果
len = ptr -
out = __ensure(p,len + 3);
return NULL;
*nptr++ = '\&';
strcpy(nptr, str);
nptr[len] = '\&';
nptr[len + 1] = '\0';
//处理 存在 &和转义字符内容
for (ptr = (c = *ptr) && ++ ++ptr) {
if (strchr(&\&\\\b\f\n\r\t&, c))
else if (c & 32) //隐藏字符的处理, 这里可以改
if ((out = __ensure(p, len + 3)) == NULL)
return NULL;
//先添加 \&
*nptr++ = '\&';
for (ptr = (c = *ptr); ++ptr) {
if (c & 31 && c != '\&' && c != '\\') {
*nptr++ = '\\';
switch (c){
case '\\':
*nptr++ = '\\';
case '\&':
*nptr++ = '\&';
case '\b':
*nptr++ = 'b';
case '\f':
*nptr++ = 'f';
case '\n':
*nptr++ = 'n';
case '\r':
*nptr++ = 'r';
case '\t':
*nptr++ = 't';
default: sprintf(nptr, &u%04x&, c);nptr += 5;
/* 不可见字符 采用 4字节字符编码 */
*nptr++ = '\&';
*nptr = '\0';
573 //这里是 递归下降 的函数声明处, 分别是处理值, 数组, object
574 static char* __print_value(cjson_t item, tstring p);
575 static char* __print_array(cjson_t item, tstring p);
576 static char* __print_object(cjson_t item, tstring p);
578 // 定义实现部分, 内部私有函数 认为 item 和 p都是存在的
579 static char* __print_value(cjson_t item, tstring p)
char* out = NULL;
switch ((item-&type) & UCHAR_MAX) { // 0xff
case _CJSON_FALSE: if ((out = __ensure(p, 6))) strcpy(out, &false&);
case _CJSON_TRUE: if ((out = __ensure(p, 5))) strcpy(out, &true&);
case _CJSON_NULL: if ((out = __ensure(p, 5))) strcpy(out, &null&);
case _CJSON_NUMBER:
out = __print_number(item, p);
case _CJSON_STRING:
out = __print_string(item-&vs, p);
case _CJSON_ARRAY:
out = __print_array(item, p);
case _CJSON_OBJECT:
out = __print_object(item, p);
595 // 同样 假定 item 和 p都是存在且不为NULL
596 static char* __print_array(cjson_t item, tstring p)
cjson_t child = item-&
// 得到孩子结点的深度
for (ncut = 0; (child); child = child-&child)
if (!ncut) { //没有孩子结点 直接空数组返回结果
char* out = NULL;
if (!(out = __ensure(p, 3)))
strcpy(out, &[]&);
if (!(ptr = __ensure(p, 1)))
return NULL;
*ptr = '[';
for (child = item-& (child); child = child-&next) {
__print_value(child, p);
p-&len = __update(p);
if (child-&next) {
if (!(ptr = __ensure(p, 2)))
return NULL;
*ptr++ = ',';
*ptr = '\0';
p-&len += 1;
if (!(ptr = __ensure(p, 2)))
return NULL;
*ptr++ = ']';
*ptr = '\0';
return p-&str +
635 // 同样 假定 item 和 p都是存在且不为NULL, 相信这些代码是安全的
636 static char* __print_object(cjson_t item, tstring p)
int i, ncut,
cjson_t child = item-&
// 得到孩子结点的深度
for (ncut = 0; child = child-&child)
if (!ncut) {
char* out = NULL;
if (!(out = __ensure(p, 3)))
strcpy(out, &{}&);
if (!(ptr = __ensure(p, 2)))
return NULL;
*ptr++ = '{';
*ptr -= '\0';
p-&len += 1;
// 根据子结点 处理
for (child = item-& (child); child = child-&next) {
__print_string(child-&key, p);
p-&len = __update(p);
//加入一个冒号
if (!(ptr = __ensure(p, 1)))
return NULL;
*ptr++ = ':';
p-&len += 1;
//继续打印一个值
__print_value(child, p);
p-&len = __update(p);
//结算最后内容
len = child-&next ? 1 : 0;
if ((ptr = __ensure(p, len + 1)) == NULL)
return NULL;
if (child-&next)
*ptr++ = ',';
*ptr = '\0';
if (!(ptr = __ensure(p, 2)))
return NULL;
*ptr++ = '}';
*ptr = '\0';
return p-&str +
689 #define _INT_CJONSTR
这里是将 cjson_t item 转换成字符串内容,需要自己free
692 * item
: cjson的具体结点
: 返回生成的item的json串内容
696 cjson_print(cjson_t item)
if ((!item) || !(p.str = malloc(sizeof(char)*_INT_CJONSTR))) {
SL_FATAL(&item:%p, p.str = malloc is error!&, item);
return NULL;
p.size = _INT_CJONSTR;
p.len = 0;
out = __print_value(item, &p); //从值处理开始, 返回最终结果
if (out == NULL) {
free(p.str);
SL_FATAL(&__print_value item:%p, p:%p is error!&, item, &p);
return NULL;
return realloc(out,strlen(out) + 1); // 体积变小 realloc返回一定成功
716 // --------------------------------- 下面是 cjson 输出部分的辅助代码 -----------------------------------------
到这里基本前期主场都完了.&后面就是玩测试了.
4.&展示&cjson&测试部分
首先展示&test_cjson_write.c&测试脚本
#include &schead.h&
#include &sclog.h&
#include &cjson.h&
// 测试 cjson 函数
int main(int argc, char* argv[])
//注册等待函数
INIT_PAUSE();
//启动日志记录功能
sl_start();
// 测试json 串
char jstr[] = &{\n\&name\&: \&Jack (\\\&Bee\\\&) Nimble\&, \n\&format\&: {\&type\&:[1, 3, 4, 5.66], \n\&height\&:
1080, \n\&interlace\&:
false}\n}&;
printf(&源码串 :\n %s\n&, jstr);
// 先生成 json 对象
cjson_t root = cjson_parse(jstr);
if (root == NULL) {
puts(&jstr 解析失败! 程序退出中....&);
exit(EXIT_FAILURE);
//这里简单测试输出内容
char* njstr = cjson_print(root);
if (njstr == NULL) {
puts(&输出内容失败,程序退出中!&);
cjson_delete(&root);
exit(EXIT_FAILURE);
//合法范围直接输出 内容
printf(&解析串 :\n %s\n&, njstr);
//解析完需要释放
free(njstr);
//解析好 一定要注意释放操作
cjson_delete(&root);
//另一个测试 输出内存值
printf(&d = %d\n&, strlen(&{\&name\&:\&Jack (\\\&Bee\\\&) Nimble\&,\&format\&:{\&type\&:[1,3,4,5.660000],\&height\&:1080,\&interlace\&:false}}&));
需要大家写一遍或看三遍.&测试结果&如下:
一切正常.&这里输出是可以的.&欢迎大家尝试了.
5.下次来个&cjson&较完整demo
  下次写好这个cjson库,&我们&测试一个下面&json&文件&实战解析一下
firefighting_rule.json&
&firefighting_rule&:
&dungeon_id&:40008,
&level_contain&:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],
&active_time&:[[1,&110000&],[4,&110000&],[5,&210000&]],
&boss_ui_head&:&UI_icon/IMG_ShiJieBoss_TouXiang.png&,
&activity_tag_icon&:&IMG_GaiBan_HuoDong_ShiJieBoss_TuBiao.png&,
&activity_tag_word&:&IMG_GaiBan_ZhuCheng_ShiJieBoss_TuBiao_MingZi.png&,
&activity_pic_json&:&UI_HuoDong_ShiJieBoss.json&,
&jinbi_buff_icon&:&UI_icon/IMG_WorldBoss_JinbiBuff_Atk.png&,
&jinbi_buff_damage&:[[8,1000],[9,1000],[11,1000],[12,1000]],
&jinbi_buff_price&:10,
&jinbi_buff_limit&:999,
&free_change&:1,
&refresh_price&:20,
&change_price&:20,
&show_hero_num&:20
解析成我们想要的那样的东西.&尝试,&追求,&按部就班 ,&人生...........................................
  错误是难免,欢迎批评指正.&下次会对cjson&进行简单总结,&再添加一些辅助函数.&一切会从简单来.}

我要回帖

更多关于 2k17辉煌生涯存档 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信