programerXiao

博客园 首页 新随笔 联系 订阅 管理

1.3 cJSON中的Print系列函数

  前面学习了cJSON的Parse系列函数,那么那只是将某个cJSON的对象进行构造为想要的JSON串,但是实际上开发的过程中往往还需要知道构造出来的cJSON对象究竟输出来是一个什么样子的。这就涉及到了4个将cJSON上下文打印出来的函数。本节我们将要逐一学习这四个cJSON_PrintXXXX系列函数。分别是

  (char *) cJSON_Print(const cJSON *item);//直接将一个cJSON对象在此函数内部进行逐一的内存分配之后变为一个便于人阅读的带有换行符、空格的JSON字符串。

  (char *) cJSON_PrintUnformatted(const cJSON *item);//直接将一个cJSON对象在此函数内部进行逐一内存分配后变为一个不包含换行符、空格而只有JSON的核心字段和值的JSON字符串

  (char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);//预先分配指定字节大小的缓冲区来装要格式化出来的JSON字符串,另外可以通过是否启用fmt标志位决定输出的JSON上下文是否包含换行符和空格。

  (cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);//这个函数是类似于sprintf,将要格式化的cJSON上下文格式化到内存块中,返回值为是否格式化成功(若目标缓冲区空间不够大,可能会格式化失败),format标识位为是否启用带有换行符和空格便于人阅读的JSON串。

  案例代码:

#include <iostream>
#include <fstream>
#include <stdlib.h>
#include "cJSON.h"
using namespace std;

/*!
* 在本节我们将着重介绍如何在Console中输出我们在内存中构造的JSON字符串,包括有格式和无格式的具体的区别,以及有缓冲区的输出和无缓冲区的输出的区别
* 我们具体要学习以下几个函数:
* cJSON_Print
* cJSON_PrintUnformatted
* cJSON_PrintBuffered
* cJSON_PrintPreallocated
*/

/*!
* @brief 测试cJSON_Print函数
* 
*/
void UseCJSON_Print(cJSON*content)
{
    cout << "使用cJSON_Print进行有格式输出的结果如下:" << endl;
    char* p = cJSON_Print(content);//由于cJSON_Print返回的char*是使用了动态内存分配的,所以使用完毕之后,必须调用cJSON_free或free函数进行释放内存
    cout << p << endl; // 将JSON的字符串输出到屏幕上
    // 将JSON写到文件中
    fstream file("cJSON_Print.json", ios::out | ios::binary);
    file.write(p, strlen(p));
    file.close();
    //一定要记得释放内存!!
    free(p);
    p = NULL;
    cout << "--------------------------------------" << endl;
    return;
}

/*!
* @brief 测试cJSON_PrintUnformatted
*/
void UseCJSON_PrintUnformatted(cJSON* content)
{
    cout << "使用UseCJSON_PrintUnformatted进行无格式输出的结果如下:" << endl;
    char* p = cJSON_PrintUnformatted(content);//同样的这个函数也返回的是char*,这意味着我们可以修改指针指向的内存的内容,而且我们还必须要在使用指针之后释放内存
    cout << p << endl;// 这个无格式输出,它就不会输出标准的JSON格式,也就是说输出的JSON里面就只有所有的字段,不会换行,也不会有空格,这就适用于屏幕空间有限,或者是对写入JSON文件的空间占用要求尽可能少的这种使用场景中
	// 将JSON写到文件中
	fstream file("cJSON_PrintUnformatted.json", ios::out | ios::binary);
	file.write(p, strlen(p));
	file.close();
	//一定要记得释放内存!!
	free(p);
	p = NULL;
    cout << "---------------------------------------------------" << endl;
}

/*!
* @brief 测试cJSON_PrintBuffered
* 
* @param prebuffer (in) 要预先分配多少个字节来容纳最终的JSON串的上下文(如果预先分配的空间足够,那么最终内部格式化JSON的时候效率就很高,如果预分配的很小,那其实内部也会补充分配直到内存足够为止)
* @param fmt       (in) 是否要启用对输出的JSON串的格式化(若为0,则不进行格式化,相当于不会输出JSON中的换行符或空格;若为1则相当于要输出换行符和空格)
* 
* @return 无
*/
void UseCJSON_PrintBuffered(cJSON* content, int prebuffer, cJSON_bool fmt)
{
    cout << "使用CJSON_PrintBuffered函数预先分配了" << prebuffer << "字节之后输出的JSON如下" << endl;
    char* p = cJSON_PrintBuffered(content, prebuffer, fmt);
    cout << p;
    cout << "------------------------------------------------------------------------------------" << endl;
    free(p);
    p = NULL;
    return;
}

int main()
{
    //1.首先手动构造一个JSON串
    char jsonBuffer[] = "{\"Name\":\"小新\",\"Age\":25,\"Birth\":\"2001-04-03\"}";
    //2.然后使用cJSON_Parse去构造出JSON对象
    cJSON* json = cJSON_Parse(jsonBuffer);

    //3.使用cJSON_Print输出JSON对象
    UseCJSON_Print(json);
	///3.1 结论:
	///3.1.1 使用cJSON_Print进行输出时,由于其返回类型为char*,所以我们可以修改返回的JSON字符串的内容。
	///3.1.2 由于其返回的char*数组是动态内存分配的,所以使用了之后需要调用free函数或者说调用cJSON_free()函数进行释放,否则会内存泄露
    ///3.1.3 cJSON_Print返回的JSON串中含义空格和换行符,它相当于是对一个JSON字段输出后就换行,这个函数很适合输出出JSON串后写入到文件中给人看,或者说直接输出到stdout中给人看。能够一览无余
    ///3.1.4 这个函数的特点是,输出的JSON内容由于含有空格和换行,所以会很占用空间(无论是写文件还是往stdout上输出),但对实际开发中,我们并不会担心空间问题,我们写JSON到文件中仍然推荐用这个函数

    //4.使用cJSON_PrintUnformatted输出JSON对象
    UseCJSON_PrintUnformatted(json);
    ///4.1 结论
    ///4.1.1 此函数和cJSON_Print函数一样,返回的char*我们可以进行修改
    ///4.1.2 和cJSON_Print一样,返回的char*在使用完毕之后需要使用内存释放函数(free或cJSON_free进行释放)
    ///4.1.3 此函数的特点是,只会输出JSON中所有的必要的字段,但不会输出换行符和空格,这个特性相比于使用cJSON_Print来说更节省资源
    ///4.1.4 和cJSON_Print相比,这个函数若类比于装稀饭的桶,cJSON_Print相当于捞稀饭的同时还会捞出很多的水分[水分和大米一起被捞走](也就是空格和换行符),而cJSON_Unformatted则相当于捞稀饭里面的大米(相当于就只捞走了干的)

    //5.使用cJSON_PrintBuffered输出JSON对象
    UseCJSON_PrintBuffered(json,4096,0);
    ///5.1 结论
    ///5.1.1 此函数也是返回的char*,那么可以修改返回的JSON内容
    ///5.1.2 此函数返回的char*在使用完毕后必须要释放(free或者是调用cJSON_free进行释放)
    ///5.1.3 此函数有三个参数分别是:
    ///5.1.3.1 const cJSON *item  要格式化输出的JSON的上下文对象
    ///5.1.3.2 int prebuffer      要预先分配多大的内存来格式化这个JSON对象(这个参数相比于前面没有预分配内存的Print函数,由于输出JSON的时候是一个char*这个char*的内存是需要分配的,但是前面的几个函数需要根据JSON上下文的大小进行动态分配,这效率就很低,这个函数就可以先指定很大的一块内存(只要堆够大,就可以直接分配出目标缓冲然后效率就很高了)一般我们建议这个参数分配4096或者是8192
    ///5.1.3.3 cJSON_bool fmt     是否要格式化输出(若为1,那么就变为适合人来阅读的JSON串[里面就含有换行符和空格]会很浪费空间但便于阅读;若为0,则里面就没有多余的换行符或空格,就只有关键的JSON字段和值,这就很节省空间(无论是对内存使用开销还是写到磁盘上),但是不方便人阅读

    //6.使用cJSON_PrintPreallocated将JSON对象格式化到一块内存里面存起来(这个函数类似于sprintf)
    char* buf = new char[4096];
    cJSON_bool rtn = cJSON_PrintPreallocated(json, buf, 4096, 0);
    if (rtn)
    {
        cout << "成功将JSON上下文格式化到了内存buf中" << endl;
        cout << "buf:" << buf << endl;
        delete[] buf;
        buf = NULL;
    }
    else
    {
        cerr << "将JSON上下文格式化到了内存buf中失败,缓冲区过小" << endl;
        delete[] buf;
        buf = NULL;
    }
    ///6.1 总结
    ///6.1.1 此函数和sprintf函数一样的,就是将格式化后的JSON上下文往内存buffer里面格式化了放
    ///6.1.2 此函数有四个参数,以下为解释
    ///6.1.2.1 cJSON *item  要格式化的JSON上下文
    ///6.1.2.2 char *buffer 要将格式化后的JSON字符串放到的目标内存缓冲区的buffer地址
    ///6.1.2.3 const int length 目标buffer的最大容量大小
    ///6.1.2.4 const cJSON_bool format 是否要启用格式输出

    //3.使用完毕后需要释放JSON上下文
    cJSON_Delete(json);
    json = NULL;
    return 0;
}

  本章小结

函数名称 函数参数以及内存管理策略 使用场景
(char *) cJSON_Print(const cJSON *item)

item:要格式化的JSON上下文;

此函数需要在内部自动分配内存(有可能会涉及到多步分配),效率较低。另外此函数会输出适合人阅读的JSON字符串(会带有JSON的空格以及换行符)

适用于需要输出到stdout的这种涉及到调试的场景中。但由于函数内部可能会涉及到对同一个JSON上下文多次内存分配操作,故此函数效率可能较低。适用于调试JSON的场景中。
(char *) cJSON_PrintUnformatted(const cJSON *item)

item:要格式化的JSON上下文

此函数和cJSON_Print一样的内存分配策略(也是由此函数内部进行分配),若JSON上下文很大的时候,可能会涉及到多次分配,效率会较低。但此函数相比于cJSON_Print来说,输出的JSON串不带有多余的空格或换行符。使用起来较为节省空间(节省屏幕的显示空间和内存空间)。

适用于需要将JSON串输出到stdout的场景中,但对于屏幕或内存空间要求较高的场景中,此函数很适合。因为它不会输出JSON中多余的空格和换行符。只有JSON中纯的关键的字段以及值。此函数也会涉及到多次内存分配操作。效率也相对较低。
(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)

item:要格式化的JSON上下文

prebuffer:要预先分配的用于格式化JSON上下文的堆空间的大小
fmt:是否要启用格式化输出(若为1,则会输出带有空格和换行符的JSON串。否则就不带有空格和换行符)
此函数的内存分配策略为先分配再进行格式化,相比于前两个函数。效率会高很多。一般建议将内存分配为4096的整数倍。这个函数就相当于厨师提前做了8笼包子,然后客人来吃就行了,若不够,后续可以在此函数内部再分配就行了,相比前两个函数效率始终高一些。

适用于将JSON串输出到stdout的场景中。另外此函数相比于前两个函数更为灵活(可以自由控制JSON串输出的形式)。并且效率更高一些。(因为有预分配机制)
(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)

item:要格式化的JSON上下文

buffer:要将格式化的JSON串格式化到的目标缓冲区的buffer地址

length:buffer的最大长度大小

format:是否要启用格式化输出

此函数的作用是将JSON对象格式化输出到内存块的buffer中。这个函数功能和sprintf有异曲同工之妙。返回的类型为1或0,若为1表示成功格式化到内存buffer中,若失败,则返回0,返回错误的原因极大可能是buffer的内存大小不够了。

这个函数用的非常多,适用于要将JSON上下文格式化到内存buffer中的场景。我们一般格式化之后可以输出到stdout上,也可以写到文件中。此函数在实际开发中用的很多。
posted on 2026-08-02 14:58  蜡笔小新Pointer  阅读(11)  评论(0)    收藏  举报