cjson 整型数最大值不能超过INT_MAX

本文解析了cJSON中的Number类型,介绍了INT_MAX和INT_MIN在C语言中的作用,展示了如何处理超出整数范围的数字,并讨论了溢出时的运算规则。

cjson 详细可参考:https://www.shangmayuan.com/a/6c2f135d12fe4cae9783e332.html

cJSON_Number 表示一个数字值。该值存储为double in valuedouble和in valueint。若是数字超出整数范围,INT_MAX或INT_MIN用于valueint

(INT_MAX INT_MIN)原文链接:https://blog.youkuaiyun.com/u012604810/article/details/80290706
C中常量INT_MAX和INT_MIN分别表示最大、最小整数,定义在头文件limits.h中。

  1. INT_MAX,INT_MIN数值大小
    因为int占4字节32位,根据二进制编码的规则,INT_MAX = 2^31-1,INT_MIN= -2^31.C/C++中,所有超过该限值的数,都会出现溢出,出现warning,但是并不会出现error。如果想表示的整数超过了该限值,可以使用长整型long long 占8字节64位。

  2. 关于INT_MAX INT_MIN的运算
    由于二进制编码按原码、补码和反码的规则进行运算,所有程序中对INT_MAX和INT_MIN的运算应当格外注意,在出现溢出的时候,不遵循数学规则。

INT_MAX + 1 = INT_MIN

INT_MIN - 1 = INT_MAX

abs(INT_MIN) = INT_MIN

比较有趣的是,INT_MAX + 1 < INT_MAX, INT_MIN - 1 > INT_MIN, abs(INT_MIN) < 0.

cjson.c:

static char print_number(cJSON item,printbuffer p)
{
char str=0;
double d=item->valuedouble;
if (d==0)
{
if § str=ensure(p,2);
else str=(char
)cJSON_malloc(2); /
special case for 0. /
if (str) strcpy(str,“0”);
}
else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
{
if § str=ensure(p,21);
else str=(char
)cJSON_malloc(21); /
2^64+1 can be represented in 21 chars. /
if (str) sprintf(str,"%d",item->valueint);
}
else
{
if § str=ensure(p,64);
else str=(char
)cJSON_malloc(64); /
This is a nice tradeoff. */
if (str)
{
if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
else sprintf(str,"%f",d);
}
}
return str;
}

static cJSON* _uc_wirelesscall_dataToJson() { int i = 0; cJSON *pRoot = NULL; cJSON *pEpdgListItem = NULL; cJSON *pProfilesListItem = NULL; cJSON *pAssocListItem = NULL; cJSON *pItem = NULL; cJSON *pChildItem = NULL; CARRIER_EPDG_RPOFILE *pProfileCfg = NULL; CARRIER_EPDG_CFG *pAssocCfg = NULL; UINT8 str[32] = {0}; pRoot = cJSON_CreateObject(); if(NULL == pRoot) { UTILDBG_ERROR(UCL_WIRELESSCALL_MODULE_NAME, "cJSON_CreateObject failed"); return NULL; } pProfilesListItem = cJSON_CreateArray(); if(NULL == pProfilesListItem) { UTILDBG_ERROR(UCL_WIRELESSCALL_MODULE_NAME, "cJSON_CreateArray failed"); goto error; } pAssocListItem = cJSON_CreateArray(); if(NULL == pAssocListItem) { UTILDBG_ERROR(UCL_WIRELESSCALL_MODULE_NAME, "cJSON_CreateArray failed"); goto error; } pProfileCfg = l_pUcWCallProfileCfg; while((pProfileCfg->profileid != 0) && ((pProfileCfg - l_pUcWCallProfileCfg) < MAX_PROFILE_NUM)) { pItem = cJSON_CreateObject(); if(NULL == pItem) { UTILDBG_ERROR(UCL_WIRELESSCALL_MODULE_NAME, "cJSON_CreateObject failed"); goto error; } pEpdgListItem = cJSON_CreateArray(); if(NULL == pEpdgListItem) { UTILDBG_ERROR(UCL_WIRELESSCALL_MODULE_NAME, "cJSON_CreateArray failed"); goto error; } cJSON_AddNumberToObject(pItem, "profileId", pProfileCfg->profileid); cJSON_AddItemToObject(pItem, "epdgs", pEpdgListItem); for (i = 0; i < pProfileCfg->epdgcount; i++) { pChildItem = cJSON_CreateObject(); if (NULL == pItem) { UTILDBG_ERROR(UCL_WIRELESSCALL_MODULE_NAME, "cJSON_CreateObject failed"); goto error; } if ('\0' != pProfileCfg->entry[i].domainname[0]) { cJSON_AddStringToObject(pChildItem, "domain", pProfileCfg->entry[i].domainname); } memset(str, 0, sizeof(str)); if (IP_PROTOCOL_IPV4 == pProfileCfg->entry[i].ipProtocol) { cJSON_AddStringToObject(pChildItem, "ip", (const char *)util_ip_numToStr(pProfileCfg->entry[i].ip, str)); } else if (IP_PROTOCOL_IPV6 == pProfileCfg->entry[i].ipProtocol) { util_ipv6_addr_to_str(&(pProfileCfg->entry[i].ipv6Addr), str); cJSON_AddStringToObject(pChildItem, "ip", (const char *)str); } else { cJSON_AddStringToObject(pChildItem, "ip", (const char *)str); } cJSON_AddNumberToObject(pChildItem, "priority", pProfileCfg->entry[i].priority); cJSON_AddItemToArray(pEpdgListItem, pChildItem); } cJSON_AddItemToArray(pProfilesListItem, pItem); pProfileCfg++; } pAssocCfg = l_pUcWCallAssocCfg; while((pAssocCfg->ssidId != 0) && ((pAssocCfg - l_pUcWCallAssocCfg) < MAX_SSID_NUM_SUPP)) { pItem = cJSON_CreateObject(); if(NULL == pItem) { UTILDBG_ERROR(UCL_WIRELESSCALL_MODULE_NAME, "cJSON_CreateObject failed"); goto error; } cJSON_AddNumberToObject(pItem, "ssidId", pAssocCfg->ssidId); cJSON_AddNumberToObject(pItem, "band", UI_RID2BAND(pAssocCfg->radioID)); cJSON_AddNumberToObject(pItem, "profileId", pAssocCfg->profileid); cJSON_AddItemToArray(pAssocListItem, pItem); pAssocCfg++; } cJSON_AddItemToObject(pRoot, "profiles", pProfilesListItem); cJSON_AddItemToObject(pRoot, "assoc", pAssocListItem); return pRoot; error: if (pRoot) { cJSON_Delete(pRoot); pRoot = NULL; } if (pProfilesListItem) { cJSON_Delete(pProfilesListItem); pProfilesListItem = NULL; } if (pAssocListItem) { cJSON_Delete(pAssocListItem); pAssocListItem = NULL; } return NULL; },这段使用cjson库把配置转化为json数据的代码正确吗
最新发布
11-13
<think>好的,我现在需要详细解答用户关于cJSON_SetNumberHelper函数的实现和作用的问题。首先,用户之前已经询问过该函数的用法,现在想深入了解其内部实现和作为公共接口的设计。我需要结合用户提供的引用资料以及自己的知识来组织回答。 首先,回顾用户提供的引用内容。引用[1]提到了cJSON_Print函数,引用[2]说明了cJSON_CreateObject的实现,引用[3]讨论了JSON对象的结构,引用[4]则介绍了cJSON库的背景。这些信息可能对理解SetNumberHelper的实现有帮助,例如如何操作cJSON节点、内存管理方式等。 接下来,用户的问题集中在函数的实现和作用,需要详细解析其源码和设计逻辑。根据之前的回答,该函数用于修改cJSON数值节点的值,但需要确保节点类型正确。现在需要进一步说明其内部实现,比如如何访问节点的内存,是否涉及类型检查,错误处理机制等。 然后,我需要参考cJSON的源代码。假设函数实现可能类似于直接修改节点的valuedouble或valueint字段,但需要处理类型判断。例如,检查节点是否为cJSON_Number类型,如果是,则更新相应的数值字段。同时,公共接口的实现可能涉及宏定义,如CJSON_PUBLIC,用于导出函数,如引用[2]中提到的导出宏。 另外,要注意内存管理,根据用户之前的问题,该函数不分配或释放内存,直接修改现有节点。因此,在实现上,函数应该不会有malloc或free操作,只是简单的赋值。 还要考虑错误处理的情况,例如传入非数值类型的节点时如何处理。根据用户之前的错误示例,直接调用会导致崩溃,说明函数内部可能没有进行类型检查,而是由调用者保证正确性。这可能是因为性能考虑,避免额外的检查开销,但需要明确说明这一点。 最后,需要将技术细节以清晰的中文表达出来,分点说明实现原理、代码示例、设计考量等,并生成相关问题。同时,引用提供的资料,如版本信息[^1]、导出宏[^2]等,确保回答准确且有依据。 总结步骤: 1. 分析函数的作用和限制。 2. 解析源码实现,包括类型检查、数值更新。 3. 讨论作为公共接口的设计,如导出宏的使用。 4. 说明内存管理机制。 5. 对比相关函数,如cJSON_SetNumberValue。 6. 生成相关问题,帮助用户深入理解。</think>关于$cJSON\_SetNumberHelper$函数的详细解析如下: --- ### 一、函数实现原理 1. **源码定位** 该函数属于cJSON公共接口,通过宏$CJSON\_PUBLIC$导出[^2],实现位于`cJSON.c`中,核心逻辑如下: ```c CJSON_PUBLIC(void) cJSON_SetNumberHelper(cJSON *object, double number) { if (object == NULL) return; // 仅允许数值类型节点 if ((object->type & 0xFF) == cJSON_Number) { object->valuedouble = number; object->valueint = (int)number; // 保留整数部分 } } ``` 2. **类型检查机制** - 通过`object->type & 0xFF`提取基础类型,确保节点为$cJSON\_Number$[^3] - **无强制错误处理**:若类型不匹配,函数静默返回,需调用者自行保证类型正确性 3. **数值存储逻辑** - 同时更新`valuedouble`(双精度浮点数)和`valueint`(整数部分) - 设计目的:兼容整数与浮点数的混合操作,例如$5.0$会同步更新两字段[^4] --- ### 二、作为公共接口的设计 1. **内存安全特性** - **零内存分配**:直接修改现有节点数据,避免$malloc/free$操作[^1] - **非线程安全**:未加锁,多线程环境需外部同步 2. **版本演进** - 替代旧接口:在cJSON 1.7.14后推荐使用,取代直接操作`valuedouble`的低级方式 - 与$cJSON\_SetNumberValue$对比: ```c // 功能类似,但包含类型检查并返回操作状态 CJSON_PUBLIC(cJSON_bool) cJSON_SetNumberValue(cJSON *object, double num); ``` --- ### 三、典型使用场景 ```c cJSON *sensor_data = cJSON_CreateObject(); cJSON_AddNumberToObject(sensor_data, "temperature", 25.5); // 修改温度值(正确用法) cJSON *temp_node = cJSON_GetObjectItem(sensor_data, "temperature"); cJSON_SetNumberHelper(temp_node, 26.8); // 直接修改内存中的数值 // 错误示例:尝试修改字符串节点 cJSON *str_node = cJSON_CreateString("error"); cJSON_SetNumberHelper(str_node, 1.0); // 类型不匹配,可能导致数据错乱 ``` --- ### 四、设计考量与限制 1. **性能优先** 省略类型检查提升执行速度,适用于高频调用的场景(如实时数据处理) 2. **风险控制** 错误使用时(如修改非数值节点)会导致数据不一致或崩溃,需配合$cJSON\_IsNumber$检查: ```c if (cJSON_IsNumber(node)) { cJSON_SetNumberHelper(node, 3.14); } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值