1、问题
cJSON本身不支持64位的整形数据解析和增加,对于部分应用场景不适用,并且cJSON适用double来存储中间数据,转换为整形可能存在精度问题。
float和double精度问题,可以参考本文 《float和double的精度》
2、优化
修改优化cJSON的代码以支持long long 格式的数据解析。
1)增加long long 结构字段
#ifdef CONFIG_CJSON_SUPPORT_64BIT
#define NUMBER_DOUBLE 1
#define NUMBER_LONGLONG 2
#endif
/* The cJSON structure: */
typedef struct cJSON
{
struct cJSON *next;
struct cJSON *prev;
struct cJSON *child;
int type;
char *valuestring;
int valueint;
double valuedouble;
char *string;
#ifdef CONFIG_CJSON_SUPPORT_64BIT
/* The type of number,double,long long or ull */
int numbertype;
long long valuelonglong;
#endif
} cJSON;
2)优化数值解析代码流程
static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
{
#ifdef CONFIG_CJSON_SUPPORT_64BIT
int scale = 0;
#endif
double number = 0;
unsigned char *after_end = NULL;
unsigned char number_c_string[64];
unsigned char decimal_point = get_decimal_point();
size_t i = 0;
if ((input_buffer == NULL) || (input_buffer->content == NULL))
{
return false;
}
for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
{
switch (buffer_at_offset(input_buffer)[i])
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '+':
case '-':
case 'e':
case 'E':
number_c_string[i] = buffer_at_offset(input_buffer)[i];
break;
case '.':
#ifdef CONFIG_CJSON_SUPPORT_64BIT
scale = 1;
#endif
number_c_string[i] = decimal_point;
break;
default:
goto loop_end;
}
}
loop_end:
number_c_string[i] = '\0';
number = strtod((const char*)number_c_string, (char**)&after_end);
if (number_c_string == after_end)
{
return false; /* parse_error */
}
item->valuedouble = number;
#ifdef CONFIG_CJSON_SUPPORT_64BIT
if(scale == 0) /* check decimal point '.' */
{
item->valuelonglong = (long long)strtoll((const char*)number_c_string, (char**)&after_end,10);
item->numbertype = NUMBER_LONGLONG;
}
else
{
item->numbertype = NUMBER_DOUBLE;
}
#endif
/* use saturation in case of overflow */
if (number >= INT_MAX)
{
item->valueint = INT_MAX;
}
else if (number <= (double)INT_MIN)
{
item->valueint = INT_MIN;
}
else
{
item->valueint = (int)number;
}
item->type = cJSON_Number;
input_buffer->offset += (size_t)(after_end - number_c_string);
return true;
}
3)优化数值打印的流程
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
{
unsigned char *output_pointer = NULL;
double d = item->valuedouble;
int length = 0;
size_t i = 0;
unsigned char number_buffer[26]; /* temporary buffer to print the number into */
unsigned char decimal_point = get_decimal_point();
if (output_buffer == NULL)
{
return false;
}
/* This checks for NaN and Infinity */
if ((d * 0) != 0)
{
length = sprintf((char*)number_buffer, "null");
}
else
{
#if CJSON_SPRINTF_FLOAT
double test;
/* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
length = sprintf((char*)number_buffer, "%1.15g", d);
/* Check whether the original double can be recovered */
if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d))
{
/* If not, print with 17 decimal places of precision */
length = sprintf((char*)number_buffer, "%1.17g", d);
}
#else
long long d64 = (long long)d;
long d32 = (long)d;
/**
* Check if 32-bit type data is overflow.
*/
#ifdef CONFIG_NEWLIB_NANO_FORMAT
assert(d32 == d64 && "Library newlib of nano mode does not support double or long-long format, please enable newlib normal mode.");
#elif defined(CONFIG_CJSON_SUPPORT_64BIT)
if(item->numbertype == NUMBER_LONGLONG)
{
length = sprintf((char*)number_buffer, "%lld", item->valuelonglong);
}
else
#endif
{
#ifdef CONFIG_CJSON_THREE_PRECISION_ENABLE
length = sprintf((char*)number_buffer, "%.3g",item->valuedouble);
#else
length = sprintf((char*)number_buffer, "%ld", d32);
if ((double)d32 != d) {
size_t precision = 14;
unsigned char *pbuf = number_buffer;
if (d < 0.0) {
d = (double)d32 - d + 0.00000000000001;
} else {
d = d - (double)d32;
}
pbuf = &number_buffer[length];
*pbuf++ = '.';
length++;
while (d > 0.0 && precision--) {
d *= 10.0;
unsigned char tmp = (unsigned char)d;
*pbuf++ = tmp + '0';
length++;
d -= (double)tmp;
}
pbuf = &number_buffer[length - 1];
while (*pbuf == '0') {
pbuf--;
length--;
}
*++pbuf = 0;
}
#endif
}
#endif
}
/* sprintf failed or buffer overrun occurred */
if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
{
return false;
}
/* reserve appropriate space in the output */
output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
if (output_pointer == NULL)
{
return false;
}
/* copy the printed number to the output and replace locale
* dependent decimal point with '.' */
for (i = 0; i < ((size_t)length); i++)
{
if (number_buffer[i] == decimal_point)
{
output_pointer[i] = '.';
continue;
}
output_pointer[i] = number_buffer[i];
}
output_pointer[i] = '\0';
output_buffer->offset += (size_t)length;
return true;
}
4)添加long long 数值解析和增加的接口
#ifdef CONFIG_CJSON_SUPPORT_64BIT
CJSON_PUBLIC(int) cJSON_Get_LongLong(const cJSON * const object, const char * key, long long* out)
{
cJSON* sub_obj = NULL;
sub_obj = get_object_item(object,key,false);
if(out == NULL || sub_obj == NULL || sub_obj->numbertype != NUMBER_LONGLONG)
{
return -1;
}
*out = sub_obj->valuelonglong;
return 0;
}
CJSON_PUBLIC(cJSON *) cJSON_CreateLongLong(long long num)
{
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
item->type = cJSON_Number;
item->valuedouble = (double)num;
item->numbertype = NUMBER_LONGLONG;
item->valuelonglong = num;
}
return item;
}
CJSON_PUBLIC(cJSON*) cJSON_AddLongLongToObject(cJSON * const object, const char * const name, const long long valuell)
{
cJSON *number_item = cJSON_CreateLongLong(valuell);
if (add_item_to_object(object, name, number_item, &global_hooks, false))
{
return number_item;
}
cJSON_Delete(number_item);
return NULL;
}
#endif
1147

被折叠的 条评论
为什么被折叠?



