cJSON icon indicating copy to clipboard operation
cJSON copied to clipboard

print_number() doesn't work with integer

Open Geartz opened this issue 4 years ago • 8 comments

I encounter an issue when I try to print JSON string with the cJSON_PrintUnformatted function.

In the sub function print_number(), i saw that "number_buffer" was filled with 5.30498947741318e-315 when item->valuedouble = 1 Is that normal ? Because it make the program crash during the following sscanf.

I used cJSON_AddNumberToObject to add number to my cJSON object.

Geartz avatar May 27 '21 15:05 Geartz

I fixed that issue by checking if the value is an integer or a float in the function.

Has anyone encountered the same problem?

Geartz avatar Jun 11 '21 12:06 Geartz

I also encountered this problem, how did you solve it?

wangguanran avatar Jun 23 '21 03:06 wangguanran

Hi, I just added a simple check in "print_number" function.

I replace this code (line 565)

/* 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) || !compare_double((double)test, d))
{
    /* If not, print with 17 decimal places of precision */
    length = sprintf((char*)number_buffer, "%1.17g", d);
}

by this one

if(item->valuedouble == item->valueint)
{
    length = sprintf((char*)number_buffer, "%d", item->valueint);
}
else
{
    /* 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) || !compare_double((double)test, d))
    {
        /* If not, print with 17 decimal places of precision */
        length = sprintf((char*)number_buffer, "%1.17g", d);
    }
}

Please tell me if it works for you.

Geartz avatar Jun 23 '21 08:06 Geartz

Hi, I just added a simple check in "print_number" function.

I replace this code (line 565)

/* 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) || !compare_double((double)test, d))
{
    /* If not, print with 17 decimal places of precision */
    length = sprintf((char*)number_buffer, "%1.17g", d);
}

by this one

if(item->valuedouble == item->valueint)
{
    length = sprintf((char*)number_buffer, "%d", item->valueint);
}
else
{
    /* 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) || !compare_double((double)test, d))
    {
        /* If not, print with 17 decimal places of precision */
        length = sprintf((char*)number_buffer, "%1.17g", d);
    }
}

Please tell me if it works for you.

It works for me , thanks so much.

scjyyhl avatar Jun 25 '21 06:06 scjyyhl

Is this embedded? If using newlib, did you add -u _printf_float and potentially -u _scanf_float to your linker command line?

Some embedded c library implementations require you to specifically enable printf for floating numbers.

nik-markovic avatar Jun 28 '21 15:06 nik-markovic

Same weird issue has happened to me with ESP8266 RTOS SDK version 3.4. While above workaround works, it's not needed to change cjSON code. It's enough to turn off "Enable 'nano' formatting options for printf/scanf family" option for Newlib in Menuconfig.

DigitalVS avatar Jul 27 '21 11:07 DigitalVS

It would be great if the fix from @Geartz could be implemented directly into cJSON. I use cJSON on embedded software where adding support for printing float is not feasible. Also the potential overhead by implementing this fix is minimal.

Jonas-Meyer97 avatar Nov 04 '21 12:11 Jonas-Meyer97

Hi,

I also had the issue with ESP8266 RTOS SDK version 3.4, but instead of disabling completely the "'nano' formatting options for printf/scanf family" (namely the NEWLIB_NANO_FORMAT configuration option) as suggested by @vitomirs, I simply added the -u_printf_float and -u_scanf_float to the linker options in esp-idf/components/newlib/component.mk (as suggested by @nik-markovic)

So COMPONENT_ADD_LDFLAGS was changed from:

COMPONENT_ADD_LDFLAGS := -lnewlib -l$(LIBC) -lm -u __errno

COMPONENT_ADD_LDFLAGS := -u_printf_float -u_scanf_float -lnewlib -l$(LIBC) -lm -u __errno

And this solved the problem, without the need for the extra check added by the merged commit (#630), which might also by wrong as pointed out in #694

davide-leoni avatar Jan 25 '24 10:01 davide-leoni