因为JSON对象与字符串需要在堆上申请/释放空间,故定义2个函数指针变量来存在函数地址。
static void* (*JSON_malloc)(size_t _Size);//申请空间的函数指针 static void (*JSON_free)(void* _Block);//释放空间的函数指针
通过调用JSONInit()函数来初始化这两个函数指针
void JSONInit(void* (*JSONmalloc)(size_t _Size), void (*JSONfree)(void* _Block))
{
JSON_malloc = JSONmalloc;
JSON_free = JSONfree;
}
解码
因为功能函数过多,这里仅介绍几个重要的函数。
解码JSON传入需要解码的JSON字符串,与对应的数据模型,即可解码。
- 检查参数
- 检查申请/释放空间函数指针是否已经赋值
- 根对象是否为空
- 调用解析对象功能函数开始解析JSON字符串
void* DecodeJSON(char* jsonStr, PJSON_MODEL_t model, unsigned int modelCount, char removeInvalidChars)
{
void* root = NULL;
JSONErrorCode = JSON_SUCCESS;
if (jsonStr == NULL || model == NULL || modelCount == 0)
{
JSONErrorCode = PARAM_IS_EMPTY;//参数为空失败
return NULL;
}
if (JSON_malloc == NULL || JSON_free == NULL)
{
JSONErrorCode = JSON_NOT_INIT;//未初始化
return NULL;
}
if (removeInvalidChars)
{
strTrim(jsonStr);
}
#if (JSON_DEBUG == 1)
printf("解码的JSON字符串长度为:%zun", strlen(jsonStr));
printf("解码的JSON字符串为:%sn", jsonStr);
#endif // (JSON_DEBUG == 1)
if (*(jsonStr + 1) == '}')
{
JSONErrorCode = DECODE_ROOT_OBJECT_NULL;//根对象是不是空对象
return NULL;
}
root = DecodeObject(jsonStr, model, modelCount);
return root;
}
解析对象
- 检查函数参数
- 检查对象为空
- 获取根对象占用的字节大小
- 为对象申请空间
- 变量对象的数据模型,依次解析JSON字符串
- 检查错误代码,出错则释放对象,函数返回NULL
static void* DecodeObject(const char* jsonStr, PJSON_MODEL_t model, unsigned int modelCount)
{
void* obj = NULL;
unsigned short objectSize = 0;
const char* value = jsonStr;
const char* nextValue = NULL;
if (jsonStr == NULL || model == NULL || modelCount == 0)
{
JSONErrorCode = PARAM_IS_EMPTY;//字符串为空 失败
return NULL;
}
if (*(value + 1) == ' ')
{
JSONErrorCode = DECODE_OBJECT_IS_EMPTY;//对象为空
return NULL;
}
value++;//跳过字符 {
nextValue = value;
for (unsigned i = 0; i < modelCount; i++)
{
if (model[i].type == JSON_TYPE_OBJECT)
{
objectSize = model[i].value.objectSize;
break;
}
}
obj = JSON_malloc(objectSize);//申请空间
if (obj == NULL)
{
JSONErrorCode = DECODE_OBJECT_FAIL_1;//为对象申请空间失败
return NULL;
}
memset(obj, 0, objectSize);
#if (JSON_DEBUG == 1)
printf("对象申请空间%pn", obj);
#endif // (JSON_DEBUG == 1)
for (unsigned int i = 1; i < modelCount; i++)
{
if ((model[i].type == JSON_TYPE_OBJECT || model[i].type == JSON_TYPE_ARRAY))
{
value = JSONSkipChildJsonStr((char**)&nextValue, model[i].type);
if (value == NULL)
{
JSONErrorCode = NOU_FIND_CHILD_ARRAY_OBJECT_END;//未找到子对象/数组的JSON字符串末尾
}
}
else
{
value = strtok_s(NULL, ",", (char**)&nextValue);
}
switch (model[i].type)
{
case JSON_TYPE_BOOL:
*(JSON_BOOL_t*)((char*)obj + model[i].offset) = DecodeBool(value, &model[i], 1);
break;
case JSON_TYPE_CHAR:
*(char*)((char*)obj + model[i].offset) = (char)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_SHORT:
*(short*)((char*)obj + model[i].offset) = (short)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_INT:
*(int*)((char*)obj + model[i].offset) = (int)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_UCHAR:
*(unsigned char*)((char*)obj + model[i].offset) = (unsigned char)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_USHORT:
*(unsigned short*)((char*)obj + model[i].offset) = (unsigned short)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_UINT:
*(unsigned int*)((char*)obj + model[i].offset) = (unsigned int)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_FLOAT:
*(float*)((char*)obj + model[i].offset) = (float)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_DOUBLE:
*(double*)((char*)obj + model[i].offset) = (double)DecodeNumberOrDouble(value, &model[i], 1);
break;
case JSON_TYPE_STRING:
*(char**)((char*)obj + model[i].offset) = DecodeString(value, &model[i], 1);
break;
case JSON_TYPE_OBJECT:
value = CheckKeyName(value, &model[i]);
if (value == NULL)
{
JSONErrorCode = DECODE_OBJECT_FAIL;//键名不一致解析失败
//释放对象申请的空间
FreeJSONObject(obj, model, modelCount);
return NULL;
}
void* childObj = NULL;
childObj = DecodeObject(value, model[i].value.child.model, model[i].value.child.count);
if (childObj == NULL)//解析子对象失败
{
if (JSONErrorCode == DECODE_OBJECT_IS_EMPTY)//是不是空对象
{
JSONErrorCode = JSON_SUCCESS;//复位错误代码
}
else
{
JSONErrorCode = DECODE_OBJECT_FAIL_2;//解析子对象失败
return NULL;
}
}
*(char**)((char*)obj + model[i].offset) = childObj;
break;
case JSON_TYPE_ARRAY:
DecodeArray(value, &model[i], (char*)obj + model[i].offset, 1);
if (JSONErrorCode == DECODE_ARRAY_IS_EMPTY)//是不是空数组
{
JSONErrorCode = JSON_SUCCESS;//复位错误代码
}
break;
default:
break;
}
if (JSONErrorCode != JSON_SUCCESS)
{
//释放对象申请的空间
FreeJSONObject(obj, model, modelCount);
return NULL;
}
}
return obj;
}
解析实数
- 检查字符串是否可读
- 转换实数
static double DecodeNumberOrDouble(const char* jsonStr, PJSON_MODEL_t model, char decodeKeyName)
{
double d = 0.0;
const char* value = jsonStr;
const char* endStr = NULL;
if (value == NULL)//检查字符串是否可读
{
return 0.0;
}
if (decodeKeyName)
{
value = CheckKeyName(jsonStr, model);
if (value == NULL)
{
JSONErrorCode = DECODE_NUMBER_DOUBLE_FAIL; //解析整数/实数失败
return 0.0;
}
}
d = strtod(value, (char**)&endStr);
if (*endStr != 'n' && *endStr != ' ' && *endStr != '}')//如果不是 null } 则解析失败
{
JSONErrorCode = DECODE_NUMBER_DOUBLE_FAIL; //解析整数/实数失败
}
return d;
}
释放对象
- 遍历对象的数据模型
- 如果是实数类型,则继续
- 字符串类型则释放空间
- 对象类型则递归调用此函数
- 数组类型则根据数组元素类型来释放空间
void FreeJSONObject(void* obj, PJSON_MODEL_t model, unsigned int modelCount)
{
void* addr = NULL;
if (obj == NULL || model == NULL || modelCount == 0)
{
JSONErrorCode = PARAM_IS_EMPTY;//参数为空失败
return;
}
if (JSON_malloc == NULL || JSON_free == NULL)
{
JSONErrorCode = JSON_NOT_INIT;//未初始化
return;
}
for (unsigned int i = 0; i < modelCount; i++)
{
switch (model[i].type)
{
case JSON_TYPE_BOOL:
case JSON_TYPE_CHAR:
case JSON_TYPE_SHORT:
case JSON_TYPE_INT:
case JSON_TYPE_UCHAR:
case JSON_TYPE_USHORT:
case JSON_TYPE_UINT:
case JSON_TYPE_FLOAT:
case JSON_TYPE_DOUBLE:
break;
case JSON_TYPE_STRING:
addr = *(char**)((char*)obj + model[i].offset);//字符串的地址
if (addr)
{
#if (JSON_DEBUG == 1)
printf("释放字符串%p %sn", addr, addr);
#endif // (JSON_DEBUG == 1)
JSON_free(addr);
}
break;
case JSON_TYPE_OBJECT:
if (model[i].keyName == NULL)
{
continue;
}
addr = *(char**)((char*)obj + model[i].offset);//对象的地址
if (addr)
{
FreeJSONObject(addr, model[i].value.child.model, model[i].value.child.count);
}
break;
case JSON_TYPE_ARRAY:
switch (model[i].value.array.type)
{
case JSON_TYPE_BOOL:
case JSON_TYPE_CHAR:
case JSON_TYPE_SHORT:
case JSON_TYPE_INT:
case JSON_TYPE_UCHAR:
case JSON_TYPE_USHORT:
case JSON_TYPE_UINT:
case JSON_TYPE_FLOAT:
case JSON_TYPE_DOUBLE:
break;
case JSON_TYPE_STRING:
for (unsigned int j = 0; j < model[i].value.array.count; j++)
{
addr = *(char**)((char*)obj + model[i].offset + j * model[i].value.array.size);
if (addr)
{
#if (JSON_DEBUG == 1)
printf("释放字符串%p %sn", addr, addr);
#endif // (JSON_DEBUG == 1)
JSON_free(addr);
}
}
break;
case JSON_TYPE_OBJECT:
for (unsigned int j = 0; j < model[i].value.array.count; j++)
{
addr = *(char**)((char*)obj + model[i].offset + j * model[i].value.array.size);
if (addr)
{
FreeJSONObject(addr, model[i].value.array.child.model, model[i].value.array.child.count);
}
}
break;
default:
break;
}
break;
default:
break;
}
}
#if (JSON_DEBUG == 1)
printf("释放对象%pn", obj);
#endif // (JSON_DEBUG == 1)
JSON_free(obj);
}
编码
JSON编码
- 先计算根对象需要的内存空间大小
- 调用编码对象功能函数编码JSON字符串
char* EncodeJSON(void* obj, PJSON_MODEL_t model, unsigned int modelCount)
{
char* encodeJSONStr = NULL;
char* str = NULL;
BYTES_t bytes = 0;
JSONErrorCode = JSON_SUCCESS;
if (obj == NULL || model == NULL || modelCount == 0)
{
JSONErrorCode = PARAM_IS_EMPTY;//函数参数无效
return NULL;
}
if (JSON_malloc == NULL || JSON_free == NULL)
{
JSONErrorCode = JSON_NOT_INIT;//未初始化
return;
}
bytes = GetObjectNeedBytes(obj, model, modelCount);
if (bytes == 0)
{
return NULL;
}
#if (JSON_DEBUG == 1)
printf("编码的JSON字符串长度为%un", bytes);
#endif // (JSON_DEBUG == 1)
bytes++;
encodeJSONStr = JSON_malloc(bytes);
if (encodeJSONStr == NULL)
{
JSONErrorCode = ENCODE_FAIL;//申请空间失败
return NULL;
}
memset(encodeJSONStr, 0, bytes);
#if (JSON_DEBUG == 1)
printf("编码的JSON字符串长度申请空间%pn", encodeJSONStr);
#endif // (JSON_DEBUG == 1)
str = encodeJSONStr;
str = EncodeObject(obj, model, modelCount, str);
*str = ' ';//添加字符串结束标志
#if (JSON_DEBUG == 1)
printf("编码的JSON字符串为%sn", encodeJSONStr);
#endif // (JSON_DEBUG == 1)
return encodeJSONStr;
}
demo
JSON字符串如下
{
"id": "0011223344",
"name": "张三",
"phone": "111-22223333",
"addr": "天安门广场",
"grade": "小学四年级",
"score": {
"math": 99.5,
"chinese": 85.5,
"english": 86,
"science": 86.5,
"history": 92
}
}
对应的结构体定义如下
typedef struct score
{
float math;
float chinese;
float english;
float science;
float history;
}score_t, * Pscore_t;
typedef struct stu
{
char* id;
char* name;
char* phone;
char* addr;
char* grade;
Pscore_t score;
}stu_t, * Pstu_t;
相应的数据模型
JSON_MODEL_t scoreModel[] =
{
JSON_ROOT_OBJECT(score_t),
JSON_FLOAT(score_t, math),
JSON_FLOAT(score_t, chinese),
JSON_FLOAT(score_t, english),
JSON_FLOAT(score_t, science),
JSON_FLOAT(score_t, history)
};
JSON_MODEL_t stuModel[] =
{
JSON_ROOT_OBJECT(stu_t),
JSON_STRING(stu_t, id),
JSON_STRING(stu_t, name),
JSON_STRING(stu_t, phone),
JSON_STRING(stu_t, addr),
JSON_STRING(stu_t, grade),
JSON_OBJECT(stu_t, score, scoreModel, sizeof(scoreModel) / sizeof(JSON_MODEL_t))
};
解码/编码
JSONInit(malloc, free);
char jsonStr[] = "
{
"id": "0011223344",
"name" : "张三",
"phone" : "111-22223333",
"addr" : "天安门广场",
"grade" : "小学四年级",
"score" : {
"math": 99.5,
"chinese" : 85.5,
"english" : 86,
"science" : 86.5,
"history" : 92
}
}
";
Pstu_t stu = DecodeJSON(jsonStr, stuModel, sizeof(stuModel) / sizeof(JSON_MODEL_t), 1);
if (stu == NULL)
{
printf("stu解码失败 errorCode = %dn", JSONErrorCode);
return;
}
if (stu->id == NULL)
{
printf("学号为空n");
}
else
{
printf("学号为%sn", stu->id);
}
if (stu->name == NULL)
{
printf("姓名为空n");
}
else
{
printf("姓名为%sn", stu->name);
}
if (stu->phone == NULL)
{
printf("手机号为空n");
}
else
{
printf("手机号为%sn", stu->phone);
}
if (stu->addr == NULL)
{
printf("住址为空n");
}
else
{
printf("住址为%sn", stu->addr);
}
if (stu->grade == NULL)
{
printf("年级为空n");
}
else
{
printf("年级为%sn", stu->grade);
}
if (stu->score == NULL)
{
printf("成绩为空n");
}
else
{
printf("数学:%.2f 语文:%.2f 英语:%.2f 科学:%.2f 历史:%.2fn",
stu->score->math, stu->score->chinese, stu->score->english, stu->score->science, stu->score->history);
}
printf("nn");
char* str = EncodeJSON(stu, stuModel, sizeof(stuModel) / sizeof(JSON_MODEL_t));
if (str == NULL)
{
printf("编码失败n");
return;
}
printf("%sn", str);
FreeJSONString(str);
FreeJSONObject(stu, stuModel, sizeof(stuModel) / sizeof(JSON_MODEL_t));
输出结果
C语言实现JSON字符串解码与编码(一)大致思路
C语言实现JSON字符串解码与编码(二)头文件介绍
C语言实现JSON字符串解码与编码(三)源代码
源代码下载链接



