前言:在linux下C语言项目中经常会使用到JSON格式,记录一次JSON格式的生成和解析
生成JSON格式,项目用来下发串口参数
int index = 0;
char buff[1024] = {0};
index += sprintf(buff + index, "{\r\n");
index += sprintf(buff + index, "\"serial_para\":\r\n");
index += sprintf(buff + index, "[\r\n");
index += sprintf(buff + index, "{\r\n");
index += sprintf(buff + index, "\"device_name\":\"_/dev/ttyS3\",\r\n");
index += sprintf(buff + index, "\"ip_addr\":\"10.20.1.83\",\r\n");
index += sprintf(buff + index, "\"ip_port\":9333,\r\n");
index += sprintf(buff + index, "\"speed\":115200,\r\n");
index += sprintf(buff + index, "\"data_bit\":8,\r\n");
index += sprintf(buff + index, "\"stop_bit\":1,\r\n");
index += sprintf(buff + index, "\"parity\":\"N\"\r\n");
index += sprintf(buff + index, "},\r\n");
index += sprintf(buff + index, "{\r\n");
index += sprintf(buff + index, "\"device_name\":\"_/dev/ttyS5\",\r\n");
index += sprintf(buff + index, "\"ip_addr\":\"10.20.1.83\",\r\n");
index += sprintf(buff + index, "\"ip_port\":9555,\r\n");
index += sprintf(buff + index, "\"speed\":115200,\r\n");
index += sprintf(buff + index, "\"data_bit\":8,\r\n");
index += sprintf(buff + index, "\"stop_bit\":1,\r\n");
index += sprintf(buff + index, "\"parity\":\"N\"\r\n");
index += sprintf(buff + index, "}\r\n");
index += sprintf(buff + index, "]\r\n");
index += sprintf(buff + index, "}\r\n");
//以上代码段生成JSON格式的buff如下
{
serial_para:
[
{
"device_name":"_/dev/ttyS3",
"ip_addr":"10.20.1.83",
"ip_port":9333,
"speed":115200,
"data_bit":8,
"stop_bit":1,
"parity":"N"
},
{
"device_name":"_/dev/ttyS5",
"ip_addr":"10.20.1.83",
"ip_port":9335,
"speed":115200,
"data_bit":8,
"stop_bit":1,
"parity":"N"
}
]
}
解析JSON格式
struct serial_para {
char dev_name[16];
char ip_addr[16];
int ip_port;
int speed;
int databit;
int stopbit;
char parity[32];
};
int handle_json_data(char *buff) {
int i = 0;
int ret = 0;
size_t array_cnt;
char tmp[32] = {0};
char msg[128] = {0};
json_object *obj, *sub_obj;
struct serial_para serial_info;
//serial_info = (struct serial_para *)malloc(sizeof(struct serial_para));
obj = sub_obj = NULL;
const char *ok_msg = {"{\"status\":\"OK\"}"};
const char *err_msg1 = {"{\"status\":\"Invalid JSON Format\"}"};
const char *err_msg2 = {"{\"status\":\"Invalid param\"}"};
obj = json_tokener_parse(buff); /* 检查是否为标准JSON格式错误返回 */
if (obj == NULL) {
strcpy(msg, err_msg1);
log_info("client data Invalid JSON Format");
return -1;
}
ret = json_object_object_get_ex(obj, "serial_para", &sub_obj); /* 从JSON格式中取出数组对象 */
if (ret != 1) {
log_info("Fails to get params");
strcpy(msg, err_msg2);
return -1;
}
enum json_type type = json_object_get_type(sub_obj); /*判断对象JSON类型为数组*/
if(type == json_type_array) {
array_cnt = json_object_array_length(sub_obj); /* 获取数据对象的个数这里返回2 */
log_info("get json array success cnt = %d", array_cnt);
for(i = 0; i < array_cnt; i++) {
json_object *array_obj = json_object_array_get_idx(sub_obj, i); /* 根据index循环获取单个数组对象 */
get_json_string(array_obj, "device_name", tmp); /* 在数组对象中取出各个key的value值 */
strcpy(serial_info.dev_name, tmp);
memset(tmp, 0, 32);
get_json_string(array_obj, "ip_addr", tmp);
strcpy(serial_info.ip_addr, tmp);
memset(tmp, 0, 32);
get_json_string(array_obj, "ip_port", tmp);
serial_info.ip_port = atoi(tmp);
memset(tmp, 0, 32);
get_json_string(array_obj, "speed", tmp);
serial_info.speed = atoi(tmp);
memset(tmp, 0, 32);
get_json_string(array_obj, "data_bit", tmp);
serial_info.databit = atoi(tmp);
memset(tmp, 0, 32);
get_json_string(array_obj, "stop_bit", tmp);
serial_info.stopbit = atoi(tmp);
memset(tmp, 0, 32);
get_json_string(array_obj, "parity", tmp);
strcpy(serial_info.parity, tmp);
memset(tmp, 0, 32);
sys_serial2net(serial_info);
memcpy(&serial_info_g[i], &serial_info, sizeof(struct serial_para));
if (array_obj != NULL) {
//json_object_put(array_obj);
}
}
}
if (obj != NULL) {
//json_object_put(obj);
}
if (sub_obj != NULL) {
//json_object_put(sub_obj);
}
strcpy(msg, ok_msg);
return 0;
}
其中json_object_put全部注释掉了,因为发现任何一个json_object_put都会导致段错误,查看API文档后发现json_object_array_get_idx函数会释放这些变量的空间,当再次释放的时候就会导致double free的段错误。以下是官网API表述。
JSON_EXPORT int json_object_put ( 结构json_object * 对象 )
减少 json_object 的引用计数,如果达到零则释放。
在执行此操作之前,您必须拥有 obj 的所有权,否则会导致引用计数不平衡,从而导致经典的 use-after-free 错误。特别是,您通常不需要调用orjson_object_put()返回的 json_object 。json_object_object_get() 、json_object_array_get_idx()
就像在调用一块内存之后一样,在调用它或它所属的任何对象之后free(),你不能使用它(除非你知道你已经调用了显式增加引用计数)。objjson_object_put()json_object_get(obj)
NULL 可能会被传递,这种情况下这是一个空操作。