cJSON - JSON 解析器设计与实现(三):类型安全的参数配置封装

基于cJSON的JSON解析器二次封装设计

JSON 解析器设计与实现

一、模块概述

在嵌入式系统中,JSON 作为一种轻量级的数据交换格式被广泛使用。虽然 cJSON 库提供了基础的 JSON 解析功能,但在实际应用中还需要考虑内存限制、类型安全等问题。本文介绍了一个基于 cJSON 的二次封装模块,提供了更安全、更易用的 JSON 处理接口。

1.1 设计目标

  • 提供简单易用的 JSON 数据处理接口
  • 确保内存和类型安全
  • 适配嵌入式系统资源限制
  • 统一的错误处理机制

1.2 核心功能

  • JSON 字符串解析与生成
  • 多种数据类型支持
  • 参数有效性验证
  • 内存管理和安全检查

二、数据结构设计

2.1 参数配置结构

typedef struct {
    const char *key;         // JSON 键名
    json_param_type_t type;  // 数据类型
    int max_size;           // 字符串最大长度
    float scale;            // 数值缩放因子
    void *value;           // 值指针
    int is_required;       // 必需标志
} json_param_config_t;

2.2 支持的数据类型

typedef enum {
    JSON_TYPE_STRING,    // 字符串类型
    JSON_TYPE_INT,       // 整数类型
    JSON_TYPE_FLOAT,     // 浮点数类型
    JSON_TYPE_DOUBLE,    // 双精度浮点
    JSON_TYPE_OBJECT,    // JSON对象
    JSON_TYPE_ARRAY      // JSON数组
} json_param_type_t;

三、核心接口实现

3.1 JSON字符串创建

int json_create(const json_param_config_t *params, int param_count, char *json_str, int size)
{
    if (!params || !json_str || size <= 0) {
        JSON_ERR("invalid param\r\n");
        return SL_ERROR;
    }

    int ret = SL_ERROR;
    cJSON *root = cJSON_CreateObject();
    if (!root) {
        JSON_ERR("create json object failed\r\n");
        return SL_ERROR;
    }

    for (int i = 0; i < param_count; i++) {
        if (params[i].value) {
            json_add_param(root, &params[i]);
        }
    }

    char *temp = cJSON_PrintUnformatted(root);
    if (temp) {
        if (snprintf(json_str, size, "%s", temp) < size) {
            ret = SL_EOK;
        }
        free(temp);
    }

    if (ret == SL_EOK) {
        JSON_PRINTF("json_create: %s\r\n", json_str);
    }
    cJSON_Delete(root);
    return ret;
}

关键实现:

  • 参数有效性检查
  • 创建JSON根对象
  • 遍历添加键值对
  • 生成JSON字符串
  • 内存管理和清理

3.2 JSON字符串解析

int json_parse(const char *json_str, const json_param_config_t *params, int param_count)
{
    if (!json_str || !params) {
        JSON_ERR("invalid param\r\n");
        return SL_ERROR;
    }

    cJSON *root = cJSON_Parse(json_str);
    if (!root) {
        JSON_ERR("parse json string failed\r\n");
        return SL_ERROR;
    }

    int ret = SL_EOK;
    for (int i = 0; i < param_count; i++) {
        cJSON *item = cJSON_GetObjectItem(root, params[i].key);
        if (item) {
            if (json_get_param(item, (json_param_config_t *)&params[i]) != SL_EOK) {
                ret = SL_ERROR;
                break;
            }
        } else if (params[i].is_required) {
            ret = SL_ERROR;
            break;
        }
    }
    if (ret == SL_EOK) {
        JSON_PRINTF("json_parse: %s\r\n", json_str);
    }
    cJSON_Delete(root);
    return ret;
}

关键实现:

  • 输入验证
  • JSON解析
  • 参数遍历
  • 数据提取转换
  • 错误处理

3.3 参数操作接口

3.3.1 参数添加
static int json_add_param(cJSON *root, const json_param_config_t *param)
{
    if (!root || !param || !param->value) {
        JSON_ERR("invalid param\r\n");
        return SL_ERROR;
    }

    switch (param->type) {
        case JSON_TYPE_STRING:
            cJSON_AddStringToObject(root, param->key, (char *)param->value);
            break;

        case JSON_TYPE_INT:
            cJSON_AddNumberToObject(root, param->key, *(int *)param->value);
            break;

        case JSON_TYPE_DOUBLE:
            cJSON_AddNumberToObject(root, param->key, *(double *)param->value);
            break;

        case JSON_TYPE_FLOAT: {
            float val = *(float *)param->value;
            if (param->scale != 0) {
                val *= param->scale;
            }
            if (fabs(val - (int)val) < 0.000001) {
                cJSON_AddNumberToObject(root, param->key, (int)val);
            } else {
                cJSON_AddNumberToObject(root, param->key, val);
            }
            break;
        }

        case JSON_TYPE_OBJECT:
        case JSON_TYPE_ARRAY:
            if (*(cJSON **)param->value) {
                cJSON_AddItemToObject(root, param->key, 
                    cJSON_Duplicate(*(cJSON **)param->value, 1));
            }
            break;

        default:
            JSON_ERR("invalid param type\r\n");
            return SL_ERROR;
    }
    return SL_EOK;
}

关键实现:

  • 类型安全检查
  • 数值转换处理
  • 浮点数精度控制
  • 对象深拷贝
3.3.2 参数获取
static int json_get_param(cJSON *item, json_param_config_t *param)
{
    if (!item || !param || !param->value) {
        JSON_ERR("invalid param\r\n");
        return SL_ERROR;
    }

    switch (param->type) {
        case JSON_TYPE_STRING: {
            if (!cJSON_IsString(item)) {
                JSON_ERR("invalid param type\r\n");
                return SL_ERROR;
            }
            strncpy((char *)param->value, item->valuestring, param->max_size - 1);
            ((char *)param->value)[param->max_size - 1] = '\0';
            break;
        }

        case JSON_TYPE_INT:
            if (!cJSON_IsNumber(item)) {
                JSON_ERR("invalid param type\r\n");
                return SL_ERROR;
            }
            *(int *)param->value = item->valueint;
            break;

        case JSON_TYPE_DOUBLE:
            if (!cJSON_IsNumber(item)) {
                JSON_ERR("invalid param type\r\n");
                return SL_ERROR;
            }
            *(double *)param->value = item->valuedouble;
            break;

        case JSON_TYPE_FLOAT:
            if (!cJSON_IsNumber(item)) {
                JSON_ERR("invalid param type\r\n");
                return SL_ERROR;
            }
            float val = (float)item->valuedouble;
            if (param->scale != 0) {
                val /= param->scale;
            }
            *(float *)param->value = val;
            break;

        case JSON_TYPE_OBJECT:
        case JSON_TYPE_ARRAY:
            *(cJSON **)param->value = cJSON_Duplicate(item, 1);
            break;

        default:
            JSON_ERR("invalid param type\r\n");
            return SL_ERROR;
    }
    return SL_EOK;
}

关键实现:

  • 类型匹配验证
  • 字符串安全拷贝
  • 数值转换和缩放
  • 复合类型深拷贝

四、使用示例

4.1 创建JSON

// 定义参数
json_param_config_t params[] = {
    {
        .key = "name",
        .type = JSON_TYPE_STRING,
        .max_size = 32,
        .value = name_buffer,
        .is_required = 1
    },
    {
        .key = "temperature",
        .type = JSON_TYPE_FLOAT,
        .scale = 100,
        .value = &temp_value,
        .is_required = 1
    }
};

// 创建JSON字符串
char json_str[256];
json_create(params, 2, json_str, sizeof(json_str));

4.2 解析JSON

const char *json = "{\"name\":\"sensor1\",\"temperature\":25.5}";
json_parse(json, params, 2);

五、注意事项

5.1 内存安全

  • 字符串缓冲区溢出检查
  • 对象深拷贝内存管理
  • 资源释放确保

5.2 类型安全

  • 严格的类型检查
  • 数值范围验证
  • 格式转换保护

5.3 错误处理

  • 统一的错误码
  • 详细的错误日志
  • 异常情况处理

六、性能优化

6.1 内存优化

  • 减少内存拷贝
  • 合理使用栈空间
  • 及时释放资源

6.2 效率优化

  • 避免重复解析
  • 优化字符串处理
  • 合理使用缓存
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值