引言:最近在做一个mqtt的项目用到cJson库的解析遇到了一些问题
我的需求:
由于每次服务器端只会来一个指令用udp协议发送到设备端,是一个封装好的了的字符串;格式就像这样子的:
Received:
{"paras":{"led":true},"service_id":"smokeDetector","command_name":"LED灯"}
sendto ret: 74
里面就一个是重要的对象就是这个 {"led":true}
但是每次来的键可能是bot可能temp不同的建,我需要写几个if来判断他。把值取出来再进行控制设备端的操作。
1.一开始我直接从buf里面取出json然后进行解析,
发现他那个解析一步然后判断一些有没有这个键值对,然后再操作,可是发现,你先检查了一个没有,然后再检查下一个键值对的时候就出现了段错误。
代码如下:
cJSON *root = cJSON_Parse(buf);
if (root == NULL)
{
printf("Error parsing JSON: %s\n", cJSON_GetErrorPtr());
continue;
}
// 解析并处理具体的指令
cJSON *paras = cJSON_GetObjectItem(root, "paras");
if (paras != NULL)
{
cJSON *temp = cJSON_GetObjectItem(paras, "temp");
if (temp != NULL )
{
// 假设我们只关心最后一个温度值
temp_values[MAX_TEMP_VALUES - 1] = temp->valueint;
printf("收到温度数据咯\n");
}
cJSON *led = cJSON_GetObjectItem(paras, "led");
if (led != NULL && led->type !=0)
{
light_button_state = 0; // ON
control_led(8, 1); // 打开D8灯
lv_obj_set_style_bg_color(light_button, lv_color_hex(0x007AFF), 0);
// 设置按钮背景颜色
lv_label_set_text(light_btn_label, "ON");
}
else if (led != NULL && led->type == 0)
{
light_button_state = 1; // OFF
control_led(8, 0); // 关闭D8灯
lv_obj_set_style_bg_color(light_button, lv_color_hex(0xFFA000), 0);
// 设置按钮背景颜色
lv_label_set_text(light_btn_label, "OFF");
}
cJSON *bot = cJSON_GetObjectItem(paras, "bot");
printf("收到的:%d\n",bot->type);
if (bot != NULL && bot->type !=0)
{
//printf("我进来了收到1了\n");
flush_button_state = 0; // ON
control_led(7, 1); // 打开D7灯
lv_obj_set_style_bg_color(flush_button, lv_color_hex(0x007AFF), 0);
// 设置按钮背景颜色
lv_label_set_text(flush_btn_label, "ON");
}
else if (bot != NULL && bot->type==0)
{
flush_button_state = 1; // OFF
control_led(7, 0); // 关闭D7灯
lv_obj_set_style_bg_color(flush_button, lv_color_hex(0xFFA000), 0);
// 设置按钮背景颜色
lv_label_set_text(flush_btn_label, "OFF");
}
cJSON_Delete(root); // 删除 cJSON 对象,释放内存
}
2.原因
后面我发现,主要原因是cjson* 这个操作会创建一个结构体,理论上应该是空的(!!!但是里面有一些被初始化的成员)
cJSON_GetObjectItem(paras, "temp"); 这个函数执行后然后没有读取的到想要的数据,返回值是空的,所以整个结构体部分空的,里面有被未初始化的成员。
但是这个时候,我去执行一个判断,if (temp != NULL )。这个结构体里面有一些成员,if里面的条件当然成立,然后就执行了if里面的语句, 可是这个结构体 里面的valueint是个NULL值。并没有东西;这样时候我再去执行这个操作,去获取里面的值temp->valueint;
if (led != NULL && led->type !=0)
而且这个if判断,不能这样写
我这个led的json结构体还没确认里面是不是正常,就立刻进去led结构体里面取这个type值就会出现段错误
就会触发内存的段错误。
3.解决方法
我们可以先进行全部的取值出来,然后再去判断,然后再进行操作,就不会触发段错误了;
if (paras != NULL)
{
cJSON *temp = cJSON_GetObjectItem(paras, "temp");
cJSON *led = cJSON_GetObjectItem(paras, "led");
cJSON *bot = cJSON_GetObjectItem(paras, "bot");
if(temp != NULL)
{
temp_n=temp->valueint;
temp_values[MAX_TEMP_VALUES - 1] = temp_n;
printf("temp里面是:%d\n",temp->valueint);
lv_label_set_text_fmt(temp_label, "temperature : %d°C", temp_values[MAX_TEMP_VALUES - 1]);
}
if (led != NULL)
{
led_n=led->type;
printf("led里面是:%d\n",led->type);
if (led_n!=0)
{
light_button_state=0;
control_led(8, 1); // 打开D8灯
lv_obj_set_style_bg_color(light_button, lv_color_hex(0x007AFF), 0); // 设置按钮背景颜色
lv_label_set_text(light_btn_label, "ON");
/* code */
}
else
{
light_button_state=1;
control_led(8, 0); // 关闭D8灯
lv_obj_set_style_bg_color(light_button, lv_color_hex(0xFFA000), 0); // 设置按钮背景颜色
lv_label_set_text(light_btn_label, "OFF");
}
}
if (bot != NULL)
{
bot_n=bot->type;
printf("bot里面是:%d\n",bot->type);
if (bot_n!=0)
{
flush_button_state = 0; // ON
control_led(7, 1); // 打开D7灯
lv_obj_set_style_bg_color(flush_button, lv_color_hex(0x007AFF), 0); // 设置按钮背景颜色
lv_label_set_text(flush_btn_label, "ON");
}
else
{
flush_button_state = 1; // OFF
control_led(7, 0); // 关闭D7灯
lv_obj_set_style_bg_color(flush_button, lv_color_hex(0xFFA000), 0); // 设置按钮背景颜色
lv_label_set_text(flush_btn_label, "OFF");
}
}