• c json实战引擎五 , 优化重构


    引言

       scjson是一个小巧的纯c跨平台小巧引擎. 适用于替换老的cJSON引擎的场景.

    数据结构和代码布局做了大量改进.优势体现在以下几个方面:

      1) 跨平台 (window 10 + VS2017 / ubuntu 16.10 + gcc 6.2 测试通过)

      2) 数据结构重构(内存结构缩减了小一半)

      3) 代码思路精简(全部加起来抛掉注释也许800行不到)

      4) 支持json文本注释特性 // or /* */

      5) 接口更少,更容易掌握全部

    本文用到的资源

      上一篇博文 c json实战引擎四 , 最后❤跳跃

      内嵌到simplec框架的源码地址 https://github.com/wangzhione/simplec

      其中需要用到的文件

        scjson.h  -> 解析json的接口文件

        scjson.c  -> 解析json的具体实现

        tstr.h    -> 和文件打交道用到的c字符串结构接口文件

        tstr.c    -> 和文件打交道用到的c字符串结构具体实现

    扯个蛋, 写了无数的代码, 还是觉得写代码还是挺有意思的O(∩_∩)O哈哈~.

      流浪记 http://music.163.com/#/song?id=26075648

    前言

      在说这里之前来点有意思点心, 不知道有木有人对malloc接口使用起来感觉很别扭.

    详细一点可以了解 C基础 内存统一入口 .这里我们加深一下对malloc内部机制的理解,

    首先看以前找的资料, 主要是linux上用户态申请内存最大大小是多少等.

      malloc 一些解释 : https://www.zhihu.com/question/20836462

    后面自己做了一些测试 

    #include <stdio.h>
    #include <stdlib.h>
    #include <limits.h>
    
    /*
     * test calloc 返回结果信息
     */
    int main(void) {
        void * node;
    
        printf("UINT_MAX = %ld.
    ", UINT_MAX);
    
        node = malloc(UINT_MAX);
        printf("malloc UINT_MAX node = %p.
    ", node);
        if (node) {
            puts("神奇!");
            free(node);
        }
    
        // 测试calloc 结果
        node = calloc(UINT_MAX, sizeof(char));
        printf("calloc UINT_MAX node = %p.
    ", node);
        if (node) {
            puts("无语");
            free(node);
        }
    
        return 0;
    }
    
    //
    // 测试结果 -> 系统蓝屏
    // 结论 -> calloc 和 malloc 的行为是系统决定, assert也许是最好的选择

    上面代码 run 之后, window 10系统直接蓝屏. 说明malloc/calloc 这类用户向系统要内存的函数, 都是不透明的.

    都存在未定义行为. 因此得到的结论是

      1. 需要分系统来处理malloc, windows申请大内存存在崩溃行为

      2. 推荐以后关于 malloc / calloc 推荐用 assert 处理

    上面是对malloc的解惑. 扯淡一点发现Microsoft 的 Visual Studio 2017 真厉害 , 黑科技太猛了, 强烈推荐尝试!!

    到这里开始逐渐开始介绍scjson的设计思路了, 这里用到一个数据结构tstr . 设计结构图如下

    完整代码可以在github上找, 还是挺不错的200行左右的代码, 加深对C字符串的理解.

    这里再扯一点, str指向内存常变, tstr指向内存不怎么变. 所以采用两块内存保存,

    方便后期优化, 例如加上字符串引用, 字符串枚举呀.

    具体可以尝试了解对cloudwu字符串的解析博文 对云风 cstring 第二次解析

    正文

       这里主要讲解scjson 解析的思路. 开篇继续扯淡, 发现C11的匿名结构体或联合体挺爽的.

    (好像C99就有).例如设计的c保存json节点结构

    struct cjson {
        struct cjson * next;      // 采用链表结构处理, 放弃二叉树结构, 优化内存
        struct cjson * child;     // type == ( _CJSON_ARRAY or _CJSON_OBJECT ) 那么 child 就不为空
    
        unsigned char type;        // 数据类型和方式定义, 一个美好的意愿
        char * key;       // json内容那块的 key名称     
        union {
            char * vs;    // type == _CJSON_STRING, 是一个字符串     
            double vd;    // type == _CJSON_NUMBER, 是一个num值, ((int)c->vd) 转成int 或 bool
        };
    };

    其中 union 中 vs 和 vd. 其实在老的C89也可以实现这种效果, 具体在linux内核中有过一个小技巧.

        union {
            char * vs; 
            double vd;
        };

    伪造实现如下, 这种方式缺点是宏污染, 搞起来麻烦, 不好看.

    union {
      char * vs;
      double vd;    
    } __v;
    #define vs __v.vs #define vd __v.vd

    我们这里scjson 解析引擎内存结构如下:

    详细一点代码类型就是

    // json中几种数据结构和方式定义, 对于程序开发而言最难的还是理解思路(思想 or 业务)
    #define _CJSON_FALSE    (0u)
    #define _CJSON_TRUE     (1u)
    #define _CJSON_NULL     (1u << 1)
    #define _CJSON_NUMBER   (1u << 2)
    #define _CJSON_STRING   (1u << 3)
    #define _CJSON_ARRAY    (1u << 4)
    #define _CJSON_OBJECT   (1u << 5)
    
    #define _CJSON_ISREF    (1u << 6)        //set 时候用如果是引用就不释放了
    #define _CJSON_ISCONST  (1u << 7)        //set 时候用, 如果是const char * 就不释放了

    上面就是解析之后的具体结构类型. 下面简单分析一下文本解析规则.

    主要思路就是递归下降分析. 到这里基本关于scjson详细设计图介绍完毕了.

    去掉注释一共也许800行代码都不到, 愿这只麻雀 ヽ(✿゚▽゚)ノ

    后记

       On s'en va (Shy'm) http://music.163.com/m/song?id=29814206&userid=16529894

          

          相濡以沫,不如相忘于江湖   --  《庄子·大宗师·天运》

          

  • 相关阅读:
    做了点数论的题
    2016日报总结
    2016在H3C
    2017春节小目标
    2016项目小总结
    明明的随机数
    计算字符个数
    字符串最后一个单词的长度
    字符串分隔
    考研回忆
  • 原文地址:https://www.cnblogs.com/life2refuel/p/6586460.html
Copyright © 2020-2023  润新知