基於cJSON及心知天氣模組化實現獲取城市氣象資訊(現在、未來)

舟清颺發表於2024-06-14

V1.0 2024年6月14日 釋出於部落格園

目錄
  • 序言
    • 功能描述
    • 執行結果示範
    • 注意!
  • 程式碼
    • weather_api.h
    • weather_api.c
    • demo.c
    • cJSON.h
    • cJSON.c
  • 參考連結

序言

功能描述

用於請求心知天氣的資訊, 現在的資訊, 未來n天的氣象資訊(免費版僅能3天).

使用域名透過TCP連線到心知天氣伺服器, 採用cJSON進行解析.

模組化實現, 可選擇英文、中文;天數;城市;

執行結果示範

天氣伺服器域名 api.seniverse.com 的IP地址是 116.62.81.138

位置 ID: WS0E9D8WN298
位置名稱: 廣州
國家: CN
位置: 廣州,廣州,廣東,中國
時區: Asia/Shanghai
時區偏移: +08:00
天氣情況: 陰
天氣程式碼: 9
溫度: 26
最後更新時間: 2024-06-14T20:52:05+08:00


城市 ID:         WS0E9D8WN298
城市名稱:        廣州
國家:            CN
具體位置:        廣州,廣州,廣東,中國
時區:            Asia/Shanghai
時區偏移:        +08:00

日期:                    2024-06-14
白天天氣現象文字:        小雨
白天天氣現象程式碼:        13
夜間天氣現象文字:        暴雨
夜間天氣現象程式碼:        16
當天最高氣溫:    31
當天最低氣溫:    26
降水量:         19.53
降水機率:        0.98
風向文字:        西南
風向角度:        225
風速:            8.4
風力等級:        2
相對溼度:        91

日期:                    2024-06-15
白天天氣現象文字:        暴雨
白天天氣現象程式碼:        16
夜間天氣現象文字:        中雨
夜間天氣現象程式碼:        14
當天最高氣溫:    31
當天最低氣溫:    26
降水量:         28.09
降水機率:        0.98
風向文字:        南
風向角度:        180
風速:            23.4
風力等級:        4
相對溼度:        87

日期:                    2024-06-16
白天天氣現象文字:        中雨
白天天氣現象程式碼:        14
夜間天氣現象文字:        雷陣雨
夜間天氣現象程式碼:        11
當天最高氣溫:    32
當天最低氣溫:    26
降水量:         18.96
降水機率:        0.97
風向文字:        南
風向角度:        180
風速:            15.3
風力等級:        3
相對溼度:        87
資料更新時間:    2024-06-14T08:00:00+08:00


信陽氣象資訊

位置 ID: WT9NG9P4ZDHG
位置名稱: 信陽
國家: CN
位置: 信陽,信陽,河南,中國
時區: Asia/Shanghai
時區偏移: +08:00
天氣情況: 晴
天氣程式碼: 1
溫度: 32
最後更新時間: 2024-06-14T20:48:23+08:00


城市 ID:         WT9NG9P4ZDHG
城市名稱:        信陽
國家:            CN
具體位置:        信陽,信陽,河南,中國
時區:            Asia/Shanghai
時區偏移:        +08:00

日期:                    2024-06-14
白天天氣現象文字:        陰
白天天氣現象程式碼:        9
夜間天氣現象文字:        晴
夜間天氣現象程式碼:        1
當天最高氣溫:    39
當天最低氣溫:    25
降水量:         0.00
降水機率:        0.00
風向文字:        東
風向角度:        90
風速:            23.4
風力等級:        4
相對溼度:        65

日期:                    2024-06-15
白天天氣現象文字:        晴
白天天氣現象程式碼:        0
夜間天氣現象文字:        陰
夜間天氣現象程式碼:        9
當天最高氣溫:    39
當天最低氣溫:    27
降水量:         0.00
降水機率:        0.00
風向文字:        北
風向角度:        0
風速:            8.4
風力等級:        2
相對溼度:        53

日期:                    2024-06-16
白天天氣現象文字:        小雨
白天天氣現象程式碼:        13
夜間天氣現象文字:        陰
夜間天氣現象程式碼:        9
當天最高氣溫:    35
當天最低氣溫:    25
降水量:         19.45
降水機率:        0.99
風向文字:        東北
風向角度:        45
風速:            3.0
風力等級:        1
相對溼度:        95
資料更新時間:    2024-06-14T08:00:00+08:00

注意!

weather_api.h中需要填寫自己的私鑰

#define KEY "XXXXXXXXX" // 自己的私鑰

程式碼

weather_api.h

#ifndef _WEATHER_API_H
#define _WEATHER_API_H
/**
 * @file name : weather_api.h
 * @brief     : 用於請求心知天氣的資訊, 現在的資訊, 未來n天的氣象資訊(免費版僅能3天).
 *              使用域名透過TCP連線到心知天氣伺服器, 採用cJSON進行解析.
 *              模組化實現, 可選擇英文、中文;天數;城市;
 * @author    : RISE_AND_GRIND@163.com
 * @date      : 2024年6月14日
 * @version   : 1.0
 * @note      :
 * CopyRight (c)  2023-2024   RISE_AND_GRIND@163.com   All Right Reseverd
 */
/***************************************標頭檔案***************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "cJSON.h"

/***************************************END******************************************/
/***************************************預處理***************************************/
// 目標伺服器ip地址 埠號
// #define IPADDR "116.62.81.138"
#define SERVERHOSTNAME "api.seniverse.com" // 伺服器域名
#define PORT 80
#define MAX_STRING_LENGTH 100 // 解析到的JSON鍵值的最大長度
#define BUFFERSIZE 4096       // 緩衝區大小
#define DAYS_COUNT 3          // 要查詢的未來幾天天氣
// 配置資訊 訪問頻限 20次/分鐘 國內370個主要城市
#define KEY "XXXXXXXXX" // 自己的私鑰
#define LOCAL "guangzhou"       // 解析的城市
#define TYPEINFO 0              // 1預設輸出解析到的資訊, 0關閉
/**
 * 國內 370 個主要城市
 * 1 天氣實況,包括天氣現象文字、程式碼和氣溫 3 項資料
 * 2 未來 3 天天氣預報,包括白天天氣現象文字及程式碼、晚間天氣現象文字及程式碼、當天最高溫度和最低溫度、風向風速
 * 3 6 項基本類生活指數,包括穿衣、紫外線強度、洗車、旅遊、感冒、運動指數
 */
/***************************************END******************************************/
/***************************************資料型別***************************************/
// 請求的位置資訊
typedef struct
{
    char id[MAX_STRING_LENGTH];              // 城市ID
    char name[MAX_STRING_LENGTH];            // 城市名稱
    char country[MAX_STRING_LENGTH];         // 國家
    char path[MAX_STRING_LENGTH];            // 具體位置
    char timezone[MAX_STRING_LENGTH];        // 時區
    char timezone_offset[MAX_STRING_LENGTH]; // 時區偏移
} Location;
// 返回指定days天數的結果 定義未來天氣結構體 未來15天/24小時  每天更新2次,8點和20點
typedef struct
{
    char date[MAX_STRING_LENGTH];                  // 日期
    char text_day[MAX_STRING_LENGTH];              // 白天天氣現象文字:陰晴多雲等
    char code_day[MAX_STRING_LENGTH];              // 白天天氣現象程式碼
    char text_night[MAX_STRING_LENGTH];            // 夜間天氣現象文字:陰晴多雲等
    char code_night[MAX_STRING_LENGTH];            // 夜間天氣現象程式碼
    char high[MAX_STRING_LENGTH];                  // 當天最高氣溫
    char low[MAX_STRING_LENGTH];                   // 當天最低氣溫
    char rainfall[MAX_STRING_LENGTH];              // 降水量:當天累計降水量,毫米(mm)
    char precip[MAX_STRING_LENGTH];                // 降水機率,範圍0~100,單位百分比(目前僅支援國外城市)
    char wind_direction[MAX_STRING_LENGTH];        // 風向文字:地面10米風向,東、東南、南、西南等
    char wind_direction_degree[MAX_STRING_LENGTH]; // 風向角度,範圍0~360, 地面10米風向,東、東南、南、西南等
    char wind_speed[MAX_STRING_LENGTH];            // 風速,單位km/h(當unit=c時)、mph(當unit=f時)
    char wind_scale[MAX_STRING_LENGTH];            // 風力等級:根據風速大小劃分的等級
    char humidity[MAX_STRING_LENGTH];              // 相對溼度:地面2米溼度,百分比%
} Daily;

// 天氣實況資訊
typedef struct
{
    char text[MAX_STRING_LENGTH];        // 天氣現象文字
    char code[MAX_STRING_LENGTH];        // 天氣現象程式碼
    char temperature[MAX_STRING_LENGTH]; // 溫度,單位為c攝氏度或f華氏度
} Now;

// 天氣實況
typedef struct
{
    Location location;                   // 請求的位置資訊
    Now now;                             //
    char last_update[MAX_STRING_LENGTH]; // 資料更新時間(該城市的本地時間)
} WeatherResults;
// 未來 3 天天氣預報
typedef struct
{
    Location location;                   // 請求的位置資訊
    Daily daily[DAYS_COUNT];             // 返回指定days天數的結果
    char last_update[MAX_STRING_LENGTH]; // 資料更新時間(該城市的本地時間)
} WeatherResultsFuture;
/***************************************END******************************************/
/**************************************函式宣告**************************************/
/** 解析天氣實況JSON資訊
 * @name      parse_weather
 * @brief     解析天氣實況JSON資訊
 * @param     json_data JSON格式的字串(未解析的格式, 從接收區收到)
 * @param     weather_results 接收天氣實況解析結果的結構體
 * @date      2024年6月14日
 * @version   1.0
 * @note      使用前提:WeatherResultsFuture weather_results_future;
 */
void parse_weather(const char *json_data, WeatherResults *weather_results);

/** 解析未來3天天氣JSON資訊
 * @name      parse_weather_future
 * @brief     解析未來3天天氣JSON資訊
 * @param     json_data JSON格式的字串(未解析的格式, 從接收區收到)
 * @param     weather_results_future 接收未來天氣解析結果的結構體
 * @date      2024年6月14日
 * @version   1.0
 * @note      使用前提:WeatherResultsFuture weather_results_future;
 */
void parse_weather_future(const char *json_data, WeatherResultsFuture *weather_results_future);
/***************************************END******************************************/
// 列印解析後的天氣實況資訊
void PrintWeatherInfo(WeatherResults const *weather_results);
// 列印解析後的未來3天天氣資訊
void PrintWeatherFutureInfo(WeatherResultsFuture const *weather_results_future);
/**
 * @brief 解析域名得到 IPv4 地址或 IPv6 地址,優先 IPv4
 * @param hostname 域名字串
 * @param ipaddr 用於接收結果的字元陣列
 * @return 解析到 IPv4 地址返回 4,解析到 IPv6 地址返回 6,失敗返回 -1
 */
int resolve_hostname(const char *hostname, char *ipaddr);
/** 連線天氣伺服器
 * @name      connectServer
 * @brief     連線天氣伺服器
 * @param     ipaddr 伺服器ip地址
 * @param     port 伺服器埠
 * @param     tcp_socket_fd 網路套接字描述符
 * @return    成功 0; 失敗-1 (會自動關閉套接字)
 * @date      2024年6月14日
 * @version   1.0
 * @note      前提: int tcp_socket_fd=-1;//建立公用網路套接字描述符
 *            注意: 會建立tcp套接字, 不會自動關閉! 需要做錯誤處理
 *            失敗會自動關閉套接字檔案, 且tcp_socket_fd=-1;
 *            成功, 用完記得手動關閉且tcp_socket_fd;
 *
 */
int connectServer(const char *ipaddr, int port, int *tcp_socket_fd);
/** 請求天氣實況資訊
 * @name      getWeatherInfo
 * @brief     請求天氣實況資訊並解析
 * @param     tcp_socket_fd 網路套接字描述符
 * @param     local 城市位置拼音 例如 "guangzhou"
 * @param     language 接收的語言 例如 "zh-Hans"表示中文  英文:"en"
 * @param     weather_results 天氣實況接收結解析結果構體
 * @date      2024年6月14日
 * @version   1.0
 * @note      中文:zh-Hans 英文:en
 *  使用前提: connectServer(); char recvbuf[BUFFERSIZE]; // 接收緩衝區    WeatherResults weather_results;
 */
void getWeatherInfo(int tcp_socket_fd, char const *local, char const *language, char *recvbuf, WeatherResults *weather_results);

/** 請求未來天氣JSON資訊
 * @name      getWeatherFutureInfo
 * @brief     請求未來天氣JSON資訊
 * @param     tcp_socket_fd 網路套接字描述符
 * @param     local 城市位置拼音 例如 "guangzhou"
 * @param     language 接收的語言 例如 "zh-Hans"表示中文  英文:"en"
 * @param     weather_results 天氣實況接收結解析結果構體
 * @date      2024年6月14日
 * @version   1.0
 * @note      中文:zh-Hans 英文:en
 *  使用前提: connectServer(); char recvbuf[BUFFERSIZE]; // 接收緩衝區    WeatherResultsFuture weather_results_future;
 */
void getWeatherFutureInfo(int tcp_socket_fd, char const *local, char const *language, char *recvbuf, WeatherResultsFuture *weather_results_future);
#endif //_WEATHER_API_H

weather_api.c

/**
 * @file name : weather_api.c
 * @brief     : 用於請求心知天氣的資訊, 現在的資訊, 未來n天的氣象資訊(免費版僅能3天).
 *              使用域名透過TCP連線到心知天氣伺服器, 採用cJSON進行解析.
 *              模組化實現, 可選擇英文、中文;天數;城市;
 * @author    : RISE_AND_GRIND@163.com
 * @date      : 2024年6月14日
 * @version   : 1.0
 * @note      :
 * CopyRight (c)  2023-2024   RISE_AND_GRIND@163.com   All Right Reseverd
 */
#include "weather_api.h"

/** 解析天氣實況JSON資訊
 * @name      parse_weather
 * @brief     解析天氣實況JSON資訊
 * @param     json_data JSON格式的字串(未解析的格式, 從接收區收到)
 * @param     weather_results 接收天氣實況解析結果的結構體
 * @date      2024年6月14日
 * @version   1.0
 * @note      使用前提:WeatherResultsFuture weather_results_future;
 */
void parse_weather(const char *json_data, WeatherResults *weather_results)
{
    //  使用cJSON庫解析JSON字串
    cJSON *json = cJSON_Parse(json_data);
    if (json == NULL)
    {
        fprintf(stderr, "解析天氣實況 JSON 錯誤\n");
        return;
    }
#if TYPEINFO

    // 把解析之後的JSON格式結構體進行輸出
    printf("實時天氣是\n%s\n", cJSON_Print(json));
#endif
    // 獲取JSON物件中的"results"陣列
    cJSON *results = cJSON_GetObjectItem(json, "results");
    if (results == NULL || !cJSON_IsArray(results))
    {
        fprintf(stderr, "查詢“results”陣列時出錯\n");
        cJSON_Delete(json);
        return;
    }

    // 獲取"results"陣列中的第一個元素
    cJSON *result = cJSON_GetArrayItem(results, 0); // 假設陣列中只有一個結果
    if (result == NULL)
    {
        fprintf(stderr, "在“results”陣列中查詢第一項時出錯\n");
        cJSON_Delete(json);
        return;
    }

    // 獲取"result"物件中的"location"物件
    cJSON *location = cJSON_GetObjectItem(result, "location");
    if (location != NULL)
    {
        // 將"location"物件中的各個欄位值複製到weather_results->location結構體中
        strncpy(weather_results->location.id, cJSON_GetObjectItem(location, "id")->valuestring, MAX_STRING_LENGTH);
        strncpy(weather_results->location.name, cJSON_GetObjectItem(location, "name")->valuestring, MAX_STRING_LENGTH);
        strncpy(weather_results->location.country, cJSON_GetObjectItem(location, "country")->valuestring, MAX_STRING_LENGTH);
        strncpy(weather_results->location.path, cJSON_GetObjectItem(location, "path")->valuestring, MAX_STRING_LENGTH);
        strncpy(weather_results->location.timezone, cJSON_GetObjectItem(location, "timezone")->valuestring, MAX_STRING_LENGTH);
        strncpy(weather_results->location.timezone_offset, cJSON_GetObjectItem(location, "timezone_offset")->valuestring, MAX_STRING_LENGTH);
    }

    // 獲取"result"物件中的"now"物件
    cJSON *now = cJSON_GetObjectItem(result, "now");
    if (now != NULL)
    {
        // 將"now"物件中的各個欄位值複製到weather_results->now結構體中
        strncpy(weather_results->now.text, cJSON_GetObjectItem(now, "text")->valuestring, MAX_STRING_LENGTH);
        strncpy(weather_results->now.code, cJSON_GetObjectItem(now, "code")->valuestring, MAX_STRING_LENGTH);
        strncpy(weather_results->now.temperature, cJSON_GetObjectItem(now, "temperature")->valuestring, MAX_STRING_LENGTH);
    }

    // 將"result"物件中的"last_update"欄位值複製到weather_results->last_update字元陣列中
    strncpy(weather_results->last_update, cJSON_GetObjectItem(result, "last_update")->valuestring, MAX_STRING_LENGTH);

    // 釋放cJSON物件
    cJSON_Delete(json);
}

/** 解析未來n天天氣JSON資訊
 * @name      parse_weather_future
 * @brief     解析未來3天天氣JSON資訊
 * @param     json_data JSON格式的字串(未解析的格式, 從接收區收到)
 * @param     weather_results_future 接收未來天氣解析結果的結構體
 * @date      2024年6月14日
 * @version   1.0
 * @note      使用前提:WeatherResultsFuture weather_results_future;
 */
void parse_weather_future(const char *json_data, WeatherResultsFuture *weather_results_future)
{
    // 使用cJSON庫解析JSON字串
    cJSON *json = cJSON_Parse(json_data);
    if (json == NULL)
    {
        fprintf(stderr, "Error parsing JSON\n");
        return;
    }
#if TYPEINFO
    // 把解析之後的JSON格式結構體進行輸出
    printf("未來天氣是\n%s\n", cJSON_Print(json));
#endif
    // 獲取JSON物件中的"results"陣列
    cJSON *results = cJSON_GetObjectItem(json, "results");
    if (results == NULL || !cJSON_IsArray(results))
    {
        fprintf(stderr, "查詢“results”陣列時出錯\n");
        cJSON_Delete(json);
        return;
    }

    // 獲取"results"陣列中的第一個元素
    cJSON *result = cJSON_GetArrayItem(results, 0); // 假設陣列中只有一個結果
    if (result == NULL)
    {
        fprintf(stderr, "在“results”陣列中查詢第一項時出錯\n");
        cJSON_Delete(json);
        return;
    }

    // 獲取"result"物件中的"location"物件
    cJSON *location = cJSON_GetObjectItem(result, "location");
    if (location != NULL)
    {
        // 將"location"物件中的各個欄位值複製到weather_results_future->location結構體中
        strncpy(weather_results_future->location.id, cJSON_GetObjectItem(location, "id")->valuestring, MAX_STRING_LENGTH);
        strncpy(weather_results_future->location.name, cJSON_GetObjectItem(location, "name")->valuestring, MAX_STRING_LENGTH);
        strncpy(weather_results_future->location.country, cJSON_GetObjectItem(location, "country")->valuestring, MAX_STRING_LENGTH);
        strncpy(weather_results_future->location.path, cJSON_GetObjectItem(location, "path")->valuestring, MAX_STRING_LENGTH);
        strncpy(weather_results_future->location.timezone, cJSON_GetObjectItem(location, "timezone")->valuestring, MAX_STRING_LENGTH);
        strncpy(weather_results_future->location.timezone_offset, cJSON_GetObjectItem(location, "timezone_offset")->valuestring, MAX_STRING_LENGTH);
    }

    // 獲取"result"物件中的"daily"陣列
    cJSON *daily = cJSON_GetObjectItem(result, "daily");
    if (daily != NULL && cJSON_IsArray(daily))
    {
        // 遍歷"daily"陣列中的每一天的天氣資料
        for (int i = 0; i < DAYS_COUNT; i++)
        {
            cJSON *day = cJSON_GetArrayItem(daily, i);
            if (day != NULL)
            {
                // 將"day"物件中的各個欄位值複製到weather_results_future->daily[i]結構體中
                strncpy(weather_results_future->daily[i].date, cJSON_GetObjectItem(day, "date")->valuestring, MAX_STRING_LENGTH);
                strncpy(weather_results_future->daily[i].text_day, cJSON_GetObjectItem(day, "text_day")->valuestring, MAX_STRING_LENGTH);
                strncpy(weather_results_future->daily[i].code_day, cJSON_GetObjectItem(day, "code_day")->valuestring, MAX_STRING_LENGTH);
                strncpy(weather_results_future->daily[i].text_night, cJSON_GetObjectItem(day, "text_night")->valuestring, MAX_STRING_LENGTH);
                strncpy(weather_results_future->daily[i].code_night, cJSON_GetObjectItem(day, "code_night")->valuestring, MAX_STRING_LENGTH);
                strncpy(weather_results_future->daily[i].high, cJSON_GetObjectItem(day, "high")->valuestring, MAX_STRING_LENGTH);
                strncpy(weather_results_future->daily[i].low, cJSON_GetObjectItem(day, "low")->valuestring, MAX_STRING_LENGTH);
                strncpy(weather_results_future->daily[i].rainfall, cJSON_GetObjectItem(day, "rainfall")->valuestring, MAX_STRING_LENGTH);
                strncpy(weather_results_future->daily[i].precip, cJSON_GetObjectItem(day, "precip")->valuestring, MAX_STRING_LENGTH);
                strncpy(weather_results_future->daily[i].wind_direction, cJSON_GetObjectItem(day, "wind_direction")->valuestring, MAX_STRING_LENGTH);

                strncpy(weather_results_future->daily[i].wind_direction_degree, cJSON_GetObjectItem(day, "wind_direction_degree")->valuestring, MAX_STRING_LENGTH);

                strncpy(weather_results_future->daily[i].wind_speed, cJSON_GetObjectItem(day, "wind_speed")->valuestring, MAX_STRING_LENGTH);
                strncpy(weather_results_future->daily[i].wind_scale, cJSON_GetObjectItem(day, "wind_scale")->valuestring, MAX_STRING_LENGTH);
                strncpy(weather_results_future->daily[i].humidity, cJSON_GetObjectItem(day, "humidity")->valuestring, MAX_STRING_LENGTH);
            }
        }
    }

    // 將"result"物件中的"last_update"欄位值複製到weather_results_future->last_update字元陣列中
    strncpy(weather_results_future->last_update, cJSON_GetObjectItem(result, "last_update")->valuestring, MAX_STRING_LENGTH);

    // 釋放cJSON物件
    cJSON_Delete(json);
}

// 列印解析後的天氣實況資訊
void PrintWeatherInfo(WeatherResults const *weather_results)
{
    // 列印解析後的結構體內容
    printf("\n");
    printf("位置 ID: %s\n", weather_results->location.id);
    printf("位置名稱: %s\n", weather_results->location.name);
    printf("國家: %s\n", weather_results->location.country);
    printf("位置: %s\n", weather_results->location.path);
    printf("時區: %s\n", weather_results->location.timezone);
    printf("時區偏移: %s\n", weather_results->location.timezone_offset);

    printf("天氣情況: %s\n", weather_results->now.text);
    printf("天氣程式碼: %s\n", weather_results->now.code);
    printf("溫度: %s\n", weather_results->now.temperature);

    printf("最後更新時間: %s\n", weather_results->last_update);
    printf("\n");
}

// 列印解析後的未來3天天氣資訊
void PrintWeatherFutureInfo(WeatherResultsFuture const *weather_results_future)
{

    // 列印解析後的結構體內容
    printf("\n");
    printf("城市 ID:\t %s\n", weather_results_future->location.id);
    printf("城市名稱:\t %s\n", weather_results_future->location.name);
    printf("國家:\t\t %s\n", weather_results_future->location.country);
    printf("具體位置:\t %s\n", weather_results_future->location.path);
    printf("時區:\t\t %s\n", weather_results_future->location.timezone);
    printf("時區偏移:\t %s\n", weather_results_future->location.timezone_offset);

    for (int i = 0; i < DAYS_COUNT; i++)
    {
        printf("\n");

        printf("日期:\t\t\t %s\n", weather_results_future->daily[i].date);
        printf("白天天氣現象文字:\t %s\n", weather_results_future->daily[i].text_day);
        printf("白天天氣現象程式碼:\t %s\n", weather_results_future->daily[i].code_day);
        printf("夜間天氣現象文字:\t %s\n", weather_results_future->daily[i].text_night);
        printf("夜間天氣現象程式碼:\t %s\n", weather_results_future->daily[i].code_night);
        printf("當天最高氣溫:\t %s\n", weather_results_future->daily[i].high);
        printf("當天最低氣溫:\t %s\n", weather_results_future->daily[i].low);
        printf("降水量:\t %s\n", weather_results_future->daily[i].rainfall);
        printf("降水機率:\t %s\n", weather_results_future->daily[i].precip);
        printf("風向文字:\t %s\n", weather_results_future->daily[i].wind_direction);
        printf("風向角度:\t %s\n", weather_results_future->daily[i].wind_direction_degree);
        printf("風速:\t\t %s\n", weather_results_future->daily[i].wind_speed);
        printf("風力等級:\t %s\n", weather_results_future->daily[i].wind_scale);
        printf("相對溼度:\t %s\n", weather_results_future->daily[i].humidity);
    }

    printf("資料更新時間:\t %s\n", weather_results_future->last_update);
    printf("\n");
}

/** 解析域名得到 IPv4 地址或 IPv6 地址
 * @brief 解析域名得到 IPv4 地址或 IPv6 地址,優先 IPv4
 * @param hostname 域名字串
 * @param ipaddr 用於接收結果的字元陣列
 * @return 解析到 IPv4 地址返回 4,解析到 IPv6 地址返回 6,失敗返回 -1
 */
int resolve_hostname(const char *hostname, char *ipaddr)
{
    // 定義 addrinfo 結構體變數,用於儲存地址資訊
    struct addrinfo hints, *res, *p;
    int errcode; // 儲存 getaddrinfo 函式的返回值
    void *ptr;   // 指向 IP 地址的指標

    // 清空 hints 結構體並設定相關引數
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;     // 不指定 IPv4 或 IPv6
    hints.ai_socktype = SOCK_STREAM; // TCP 流套接字

    // 呼叫 getaddrinfo 函式獲取主機名對應的地址資訊
    errcode = getaddrinfo(hostname, NULL, &hints, &res);
    if (errcode != 0)
    {
        // 如果 getaddrinfo 返回非零值,則表示出錯,列印錯誤資訊並返回 -1
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(errcode));
        return -1;
    }

    // 遍歷返回的地址資訊連結串列
    for (p = res; p != NULL; p = p->ai_next)
    {
        // 判斷地址族是否為 IPv4
        if (p->ai_family == AF_INET)
        {
            // 將 IPv4 地址賦給 ptr
            ptr = &((struct sockaddr_in *)p->ai_addr)->sin_addr;
            // 將地址轉換為字串形式,並儲存在 ipaddr 中
            inet_ntop(p->ai_family, ptr, ipaddr, INET6_ADDRSTRLEN);
            freeaddrinfo(res); // 釋放 getaddrinfo 分配的記憶體
            return 4;          // 返回 4 表示解析到 IPv4 地址
        }
    }

    // 如果沒有找到 IPv4 地址,繼續尋找 IPv6 地址
    for (p = res; p != NULL; p = p->ai_next)
    {
        // 判斷地址族是否為 IPv6
        if (p->ai_family == AF_INET6)
        {
            // 將 IPv6 地址賦給 ptr
            ptr = &((struct sockaddr_in6 *)p->ai_addr)->sin6_addr;
            // 將地址轉換為字串形式,並儲存在 ipaddr 中
            inet_ntop(p->ai_family, ptr, ipaddr, INET6_ADDRSTRLEN);
            freeaddrinfo(res); // 釋放 getaddrinfo 分配的記憶體
            return 6;          // 返回 6 表示解析到 IPv6 地址
        }
    }

    // 如果沒有找到任何地址,釋放 getaddrinfo 分配的記憶體並返回 -1
    freeaddrinfo(res);
    return -1;
}

/** 連線天氣伺服器
 * @name      connectServer
 * @brief     連線天氣伺服器
 * @param     ipaddr 伺服器ip地址
 * @param     port 伺服器埠
 * @param     tcp_socket_fd 網路套接字描述符
 * @return    成功 0; 失敗-1 (會自動關閉套接字)
 * @date      2024年6月14日
 * @version   1.0
 * @note      前提: int tcp_socket_fd=-1;//建立公用網路套接字描述符
 *            注意: 會建立tcp套接字, 不會自動關閉! 需要做錯誤處理
 *            失敗會自動關閉套接字檔案, 且tcp_socket_fd=-1;
 *            成功, 用完記得手動關閉且tcp_socket_fd;
 *
 */
int connectServer(const char *ipaddr, int port, int *tcp_socket_fd)
{
    /**********************1.建立TCP套接字**********************/
    *tcp_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (*tcp_socket_fd == -1)
    {
        fprintf(stderr, "建立TCP套接字錯誤, errno:%d,%s\n", errno, strerror(errno));
        exit(1);
    }

    /******************2.發起連線請求,等待接受伺服器接受連線 建立TCP連線*******************/
    struct sockaddr_in dest_addr;
    dest_addr.sin_family = AF_INET;                // 協議族,是固定的
    dest_addr.sin_port = htons(PORT);              // 伺服器埠,必須轉換為網路位元組序
                                                   // dest_addr.sin_addr.s_addr = inet_addr(IPADDR); // 伺服器地址
    dest_addr.sin_addr.s_addr = inet_addr(ipaddr); // 伺服器地址

    /******************3. 客戶端連線成功*******************************/
    int ret = connect(*tcp_socket_fd, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
    if (ret < 0)
    {
        fprintf(stderr, "客戶端連線失敗, errno:%d,%s\n", errno, strerror(errno));
        close(*tcp_socket_fd);
        printf("TCP套接字已經關閉!\n");
        *tcp_socket_fd = -1; // 恢復失敗的情況
        return -1;
    }
    return 0;
}

/** 請求天氣實況資訊
 * @name      getWeatherInfo
 * @brief     請求天氣實況資訊並解析
 * @param     tcp_socket_fd 網路套接字描述符
 * @param     local 城市位置拼音 例如 "guangzhou"
 * @param     language 接收的語言 例如 "zh-Hans"表示中文  英文:"en"
 * @param     weather_results 天氣實況接收結解析結果構體
 * @date      2024年6月14日
 * @version   1.0
 * @note      中文:zh-Hans 英文:en
 *  使用前提: connectServer(); char recvbuf[BUFFERSIZE]; // 接收緩衝區    WeatherResults weather_results;
 */
void getWeatherInfo(int tcp_socket_fd, char const *local, char const *language, char *recvbuf, WeatherResults *weather_results)
{
    /**************************4. 構建實時天氣HTTP請求內容****************************************/
    // 用於儲存HTTP的請求內容: 請求行 + 請求欄位 + \r\n + 請求包體(可選)
    char reqbuf[1024] = {0}; // 儲存http請求內容臨時快取區
    sprintf(reqbuf, "GET https://api.seniverse.com/v3/weather/now.json?key=%s&location=%s&language=%s&unit=c "
                    "HTTP/1.1"
                    "\r\n"
                    "Host:api.seniverse.com\r\n"
                    "\r\n",
            KEY, local, language);
    /**************************5. 傳送http請求內容****************************************/
    // 雙方建立連線,此時可以利用HTTP協議傳送請求資訊,並等待伺服器的響應  基於請求/響應
    send(tcp_socket_fd, reqbuf, strlen(reqbuf), 0);
    /**************************6. 等待伺服器的響應****************************************/
    /*************請求實時天氣**************** */
    bzero(recvbuf, BUFFERSIZE); // 清除緩衝區
    // 第一次返回的響應引數
    recv(tcp_socket_fd, recvbuf, BUFFERSIZE, 0); // 從TCP套接字接收資料

#if TYPEINFO
    printf("%s\n", recvbuf); // 列印接收到的響應引數
#endif
    bzero(recvbuf, BUFFERSIZE);
    // 第二次返回的響應包體
    recv(tcp_socket_fd, recvbuf, BUFFERSIZE, 0);
#if TYPEINFO
    printf("%s\n", recvbuf); // 列印接收到的響應包體
#endif
    /*************解析實時天氣**************** */
    parse_weather(recvbuf, weather_results); // 呼叫解析函式,解析接收到的JSON資料並填充結構體

    // 列印解析後的結構體內容
    PrintWeatherInfo(weather_results);
}

/** 請求未來天氣JSON資訊
 * @name      getWeatherFutureInfo
 * @brief     請求未來天氣JSON資訊
 * @param     tcp_socket_fd 網路套接字描述符
 * @param     local 城市位置拼音 例如 "guangzhou"
 * @param     language 接收的語言 例如 "zh-Hans"表示中文  英文:"en"
 * @param     weather_results 天氣實況接收結解析結果構體
 * @date      2024年6月14日
 * @version   1.0
 * @note      中文:zh-Hans 英文:en
 *  使用前提: connectServer(); char recvbuf[BUFFERSIZE]; // 接收緩衝區    WeatherResultsFuture weather_results_future;
 */
void getWeatherFutureInfo(int tcp_socket_fd, char const *local, char const *language, char *recvbuf, WeatherResultsFuture *weather_results_future)
{
    /*********************************請求未來2天天氣************************************** */
    /**************************4. 構建未來天氣HTTP請求內容****************************************/
    // 用於儲存HTTP的請求內容: 請求行 + 請求欄位 + \r\n + 請求包體(可選)
    char reqbuf[1024] = {0}; // 儲存http請求內容臨時快取區
    sprintf(reqbuf, "GET https://api.seniverse.com/v3/weather/daily.json?key=%s&location=%s&language=%s&unit=c&start=0&days=%d "
                    "HTTP/1.1"
                    "\r\n"
                    "Host:api.seniverse.com\r\n"
                    "\r\n",
            KEY, local, language, DAYS_COUNT);
    /**************************5. 傳送http請求內容****************************************/
    // 雙方建立連線,此時可以利用HTTP協議傳送請求資訊,並等待伺服器的響應  基於請求/響應
    send(tcp_socket_fd, reqbuf, strlen(reqbuf), 0);

    /**************************6. 等待伺服器的響應****************************************/
    /*************請求實時天氣**************** */
    bzero(recvbuf, BUFFERSIZE); // 清空接收緩衝區
    // 第一次返回的響應引數
    recv(tcp_socket_fd, recvbuf, BUFFERSIZE, 0); // 從TCP套接字接收資料
#if TYPEINFO
    printf("%s\n", recvbuf); // 列印接收到的響應引數
#endif                       // 列印接收到的資料
    bzero(recvbuf, BUFFERSIZE);
    // 第二次返回的響應包體
    recv(tcp_socket_fd, recvbuf, BUFFERSIZE, 0);
#if TYPEINFO
    printf("%s\n", recvbuf); // 列印接收到的響應包體
#endif
    /*************解析未來天氣**************** */

    parse_weather_future(recvbuf, weather_results_future); // 呼叫解析函式,解析接收到的JSON資料並填充結構體
    // 列印解析後的結構體內容
    PrintWeatherFutureInfo(weather_results_future);
}

// 使用示範
#if 0
#include <stdio.h>
#include "cJSON.h"
#include "weather_api.h"

int main(int argc, char const *argv[])
{
    /***********域名解析****************/
    char ipaddr[64] = {0};
    if (resolve_hostname(SERVERHOSTNAME, ipaddr) != -1)
    {
        printf("天氣伺服器域名 %s 的IP地址是 %s\n", SERVERHOSTNAME, ipaddr);
    }
    else
    {
        printf(" %s 解析域名失敗\n", SERVERHOSTNAME);
    }
    // TCP連線伺服器
    int tcp_socket_fd = -1;
    if (connectServer(ipaddr, PORT, &tcp_socket_fd) != 0)
    {
        perror("連線天氣伺服器失敗");
        return -1;
    }

    /**************************請求實時天氣HTTP請求****************************************/
    char recvbuf[BUFFERSIZE]; // 接收緩衝區
    WeatherResults weather_results;
    getWeatherInfo(tcp_socket_fd, LOCAL, "zh-Hans", recvbuf, &weather_results);

    WeatherResultsFuture weather_results_future;
    getWeatherFutureInfo(tcp_socket_fd, LOCAL, "zh-Hans", recvbuf, &weather_results_future);
    printf("\n信陽氣象資訊\n");
    getWeatherInfo(tcp_socket_fd, "xinyang", "zh-Hans", recvbuf, &weather_results);
    getWeatherFutureInfo(tcp_socket_fd, "xinyang", "zh-Hans", recvbuf, &weather_results_future);
    close(tcp_socket_fd);
    return 0;
}

#endif

demo.c

下面是使用示範

#include <stdio.h>
#include "weather_api.h"

int main(int argc, char const *argv[])
{
    /***********域名解析****************/
    char ipaddr[64] = {0};
    if (resolve_hostname(SERVERHOSTNAME, ipaddr) != -1)
    {
        printf("天氣伺服器域名 %s 的IP地址是 %s\n", SERVERHOSTNAME, ipaddr);
    }
    else
    {
        printf(" %s 解析域名失敗\n", SERVERHOSTNAME);
    }
    // TCP連線伺服器
    int tcp_socket_fd = -1;
    if (connectServer(ipaddr, PORT, &tcp_socket_fd) != 0)
    {
        perror("連線天氣伺服器失敗");
        return -1;
    }

    /**************************請求實時天氣HTTP請求****************************************/
    char recvbuf[BUFFERSIZE]; // 接收緩衝區
    WeatherResults weather_results;
    getWeatherInfo(tcp_socket_fd, LOCAL, "zh-Hans", recvbuf, &weather_results);

    WeatherResultsFuture weather_results_future;
    getWeatherFutureInfo(tcp_socket_fd, LOCAL, "zh-Hans", recvbuf, &weather_results_future);
    printf("\n信陽氣象資訊\n");
    getWeatherInfo(tcp_socket_fd, "xinyang", "zh-Hans", recvbuf, &weather_results);
    getWeatherFutureInfo(tcp_socket_fd, "xinyang", "zh-Hans", recvbuf, &weather_results_future);
    close(tcp_socket_fd);
    return 0;
}

cJSON.h

下面是我漢化過的cJSON.h

// clang-format off

/*
  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/
/*
  版權所有 (c) 2009-2017 Dave Gamble 和 cJSON 貢獻者

  特此免費授予任何獲得本軟體及相關文件檔案(“軟體”)副本的個人,不受限制地處理本軟體,包括但不限於使用、複製、修改、合併、釋出、分發、再許可和/或銷售軟體副本,並允許向其提供本軟體的人員這樣做,須符合以下條件:

  上述版權宣告和本許可宣告應包含在本軟體的所有副本或主要部分中。

  本軟體按“原樣”提供,不提供任何形式的明示或暗示擔保,包括但不限於適銷性、適用性和非侵權的擔保。在任何情況下,作者或版權持有人均不對因本軟體或本軟體的使用或其他交易引起的任何索賠、損害或其他責任承擔責任,無論是在合同訴訟中、侵權行為中還是其他方面。
*/

#ifndef cJSON__h
#define cJSON__h

#ifdef __cplusplus
extern "C"
{
#endif

#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif

#ifdef __WINDOWS__

  /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention.  For windows you have 3 define options:

  CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
  CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
  CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol

  For *nix builds that support visibility attribute, you can define similar behavior by

  setting default visibility to hidden by adding
  -fvisibility=hidden (for gcc)
  or
  -xldscope=hidden (for sun cc)
  to CFLAGS

  then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does

  */
  /* 在為 Windows 編譯時,我們指定一個特定的呼叫約定,以避免在從具有不同預設呼叫約定的專案中呼叫時出現問題。對於 Windows,有 3 個定義選項:

  CJSON_HIDE_SYMBOLS - 在不希望匯出符號時定義
  CJSON_EXPORT_SYMBOLS - 在庫構建時定義以匯出符號(預設)
  CJSON_IMPORT_SYMBOLS - 在希望匯入符號時定義

  對於支援可見性屬性的 *nix 構建,您可以透過以下方式定義類似的行為:

  透過新增 -fvisibility=hidden(對於 gcc)或 -xldscope=hidden(對於 sun cc)到 CFLAGS 來設定預設可見性為隱藏

  然後使用 CJSON_API_VISIBILITY 標誌以與 CJSON_EXPORT_SYMBOLS 相同的方式“匯出”相同的符號
  */
#define CJSON_CDECL __cdecl
#define CJSON_STDCALL __stdcall

/* export symbols by default, this is necessary for copy pasting the C and header file */
/* 預設匯出符號,這是複製貼上 C 和標頭檔案所必需的 */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_EXPORT_SYMBOLS
#endif

#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type CJSON_STDCALL
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
#endif
#else /* !__WINDOWS__ */
#define CJSON_CDECL
#define CJSON_STDCALL

#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
#endif

/* project version */
/* 專案版本 */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 18

#include <stddef.h>

/* cJSON Types: */
/* cJSON 型別: */
#define cJSON_Invalid (0)
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_Raw (1 << 7) /* raw json */ /* 原始 JSON */

#define cJSON_IsReference 256
#define cJSON_StringIsConst 512

  /* The cJSON structure: */
  /* cJSON 結構體定義: */
  typedef struct cJSON
  {
    /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
    /* next/prev 允許您遍歷陣列/物件鏈。或者,使用 GetArraySize/GetArrayItem/GetObjectItem */
    struct cJSON *next;
    struct cJSON *prev;
    /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
    /* 陣列或物件項將具有指向陣列/物件中項鍊的子指標。 */
    struct cJSON *child;

    /* The type of the item, as above. */
    /* 專案的型別,如上所述。 */
    int type;

    /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
    /* 專案的字串,如果 type==cJSON_String 和 type == cJSON_Raw */
    char *valuestring;
    /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    /* 寫入 valueint 已棄用,請改用 cJSON_SetNumberValue */
    int valueint;
    /* The item's number, if type==cJSON_Number */
    /* 專案的數字,如果 type==cJSON_Number */
    double valuedouble;

    /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
    /* 專案的名稱字串,如果該專案是物件的子項或在物件的子項列表中。 */
    char *string;
  } cJSON;

  /* cJSON 鉤子函式結構體 */
  typedef struct cJSON_Hooks
  {
    /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
    /* malloc/free 在 Windows 上是 CDECL,無論編譯器的預設呼叫約定如何,因此確保鉤子允許直接傳遞這些函式。 */
    void *(CJSON_CDECL *malloc_fn)(size_t sz);
    void(CJSON_CDECL *free_fn)(void *ptr);
  } cJSON_Hooks;

  typedef int cJSON_bool;

  /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
   * This is to prevent stack overflows. */
  /* 限制陣列/物件巢狀的深度,超過此深度 cJSON 將拒絕解析。防止堆疊溢位。 */
#ifndef CJSON_NESTING_LIMIT
#define CJSON_NESTING_LIMIT 1000
#endif

  /* returns the version of cJSON as a string */
  /**
   * @name      cJSON_Version
   * @brief     返回 cJSON 版本號的字串
   * @return    const char* 版本號字串
   */
  CJSON_PUBLIC(const char *)  cJSON_Version(void);

  /* Supply malloc, realloc and free functions to cJSON */
  /**
   * @name      cJSON_InitHooks
   * @brief     提供 malloc、realloc 和 free 函式給 cJSON 使用
   * @param     hooks cJSON_Hooks 結構體指標,包含自定義的 malloc 和 free 函式
   */
  CJSON_PUBLIC(void)  cJSON_InitHooks(cJSON_Hooks *hooks);

  /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
  /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
  /**
   * @name      cJSON_Parse
   * @brief     解析 JSON 字串並返回 cJSON 物件
   * @param     value JSON 字串
   * @return    cJSON* 解析後的 cJSON 物件
   * @note      呼叫者負責釋放返回的 cJSON 物件(使用 cJSON_Delete)
   */
  CJSON_PUBLIC(cJSON *)  cJSON_Parse(const char *value);
  /**
   * @name      cJSON_ParseWithLength
   * @brief     解析指定長度的 JSON 字串並返回 cJSON 物件
   * @param     value JSON 字串
   * @param     buffer_length 字串長度
   * @return    cJSON* 解析後的 cJSON 物件
   * @note      呼叫者負責釋放返回的 cJSON 物件(使用 cJSON_Delete)
   */
  CJSON_PUBLIC(cJSON *)  cJSON_ParseWithLength(const char *value, size_t buffer_length);
  /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
  /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
  /**
   * @name      cJSON_ParseWithOpts
   * @brief     解析 JSON 字串並返回 cJSON 物件,允許指定是否要求 JSON 以 null 結尾,並檢索解析結束的指標
   * @param     value JSON 字串
   * @param     return_parse_end 解析結束的指標
   * @param     require_null_terminated 是否要求 JSON 以 null 結尾
   * @return    cJSON* 解析後的 cJSON 物件
   * @note      呼叫者負責釋放返回的 cJSON 物件(使用 cJSON_Delete)
   */
  CJSON_PUBLIC(cJSON *)  cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
  /**
   * @name      cJSON_ParseWithLengthOpts
   * @brief     解析指定長度的 JSON 字串並返回 cJSON 物件,允許指定是否要求 JSON 以 null 結尾,並檢索解析結束的指標
   * @param     value JSON 字串
   * @param     buffer_length 字串長度
   * @param     return_parse_end 解析結束的指標
   * @param     require_null_terminated 是否要求 JSON 以 null 結尾
   * @return    cJSON* 解析後的 cJSON 物件
   * @note      呼叫者負責釋放返回的 cJSON 物件(使用 cJSON_Delete)
   */
  CJSON_PUBLIC(cJSON *)  cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);

  /* Render a cJSON entity to text for transfer/storage. */

  /**
   * @name      cJSON_Print
   * @brief     將 cJSON 物件渲染為文字(帶格式)
   * @param     item cJSON 物件
   * @return    char* 渲染後的文字
   * @note      呼叫者負責釋放返回的字串(使用 stdlib free、cJSON_Hooks.free_fn 或 cJSON_free)
   */
  CJSON_PUBLIC(char *)  cJSON_Print(const cJSON *item);

  /* Render a cJSON entity to text for transfer/storage without any formatting. */
  /**
   * @name      cJSON_PrintUnformatted
   * @brief     將 cJSON 物件渲染為文字(無格式)
   * @param     item cJSON 物件
   * @return    char* 渲染後的文字
   * @note      呼叫者負責釋放返回的字串(使用 stdlib free、cJSON_Hooks.free_fn 或 cJSON_free)
   */
  CJSON_PUBLIC(char *)  cJSON_PrintUnformatted(const cJSON *item);

  /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
  /**
   * @name      cJSON_PrintBuffered
   * @brief     使用緩衝策略將 cJSON 物件渲染為文字
   * @param     item cJSON 物件
   * @param     prebuffer 預緩衝大小
   * @param     fmt 是否格式化輸出
   * @return    char* 渲染後的文字
   * @note      呼叫者負責釋放返回的字串(使用 stdlib free、cJSON_Hooks.free_fn 或 cJSON_free)
   */
  CJSON_PUBLIC(char *)  cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
  /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
  /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
  /**
   * @name      cJSON_PrintPreallocated
   * @brief     使用已分配的緩衝區將 cJSON 物件渲染為文字
   * @param     item cJSON 物件
   * @param     buffer 已分配的緩衝區
   * @param     length 緩衝區長度
   * @param     format 是否格式化輸出
   * @return    cJSON_bool 成功返回 1,失敗返回 0
   * @note      呼叫者對緩衝區完全負責
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
  /* Delete a cJSON entity and all subentities. */
  /**
   * @name      cJSON_Delete
   * @brief     刪除 cJSON 物件及其所有子物件
   * @param     item cJSON 物件
   */
  CJSON_PUBLIC(void)  cJSON_Delete(cJSON *item);

  /* Returns the number of items in an array (or object). */
  /**
   * @name      cJSON_GetArraySize
   * @brief     返回陣列(或物件)中的項數
   * @param     array cJSON 陣列
   * @return    int 陣列中的項數
   */
  CJSON_PUBLIC(int)  cJSON_GetArraySize(const cJSON *array);

  /* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
  /**
   * @name      cJSON_GetArrayItem
   * @brief     從陣列中檢索指定索引的項
   * @param     array cJSON 陣列
   * @param     index 索引
   * @return    cJSON* 檢索到的項,失敗返回 NULL
   */
  CJSON_PUBLIC(cJSON *)  cJSON_GetArrayItem(const cJSON *array, int index);
  /* Get item "string" from object. Case insensitive. */

  /**
   * @name      cJSON_GetObjectItem
   * @brief     從物件中獲取指定名稱的項(不區分大小寫)
   * @param     object cJSON 物件
   * @param     string 項的名稱
   * @return    cJSON* 檢索到的項
   */
  CJSON_PUBLIC(cJSON *)  cJSON_GetObjectItem(const cJSON *const object, const char *const string);
  /**
   * @name      cJSON_GetObjectItemCaseSensitive
   * @brief     從物件中獲取指定名稱的項(區分大小寫)
   * @param     object cJSON 物件
   * @param     string 項的名稱
   * @return    cJSON* 檢索到的項
   */
  CJSON_PUBLIC(cJSON *)  cJSON_GetObjectItemCaseSensitive(const cJSON *const object, const char *const string);

  /**
   * @name      cJSON_HasObjectItem
   * @brief     檢查物件中是否存在指定名稱的項
   * @param     object cJSON 物件
   * @param     string 項的名稱
   * @return    cJSON_bool 存在返回 1,不存在返回 0
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_HasObjectItem(const cJSON *object, const char *string);
  /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */

  /**
   * @name      cJSON_GetErrorPtr
   * @brief     獲取解析失敗的錯誤指標
   * @return    const char* 錯誤指標
   */
  CJSON_PUBLIC(const char *)  cJSON_GetErrorPtr(void);

  /* Check item type and return its value */
  /**
   * @name      cJSON_GetStringValue
   * @brief     檢查項型別並返回其字串值
   * @param     item cJSON 項
   * @return    char* 字串值
   */
  CJSON_PUBLIC(char *)  cJSON_GetStringValue(const cJSON *const item);
  /**
   * @name      cJSON_GetNumberValue
   * @brief     檢查項型別並返回其數值
   * @param     item cJSON 項
   * @return    double 數值
   */
  CJSON_PUBLIC(double)  cJSON_GetNumberValue(const cJSON *const item);

  /* These functions check the type of an item */
  /* 以下函式檢查項的型別 */
  CJSON_PUBLIC(cJSON_bool)  cJSON_IsInvalid(const cJSON *const item);
  CJSON_PUBLIC(cJSON_bool)  cJSON_IsFalse(const cJSON *const item);
  CJSON_PUBLIC(cJSON_bool)  cJSON_IsTrue(const cJSON *const item);
  CJSON_PUBLIC(cJSON_bool)  cJSON_IsBool(const cJSON *const item);
  CJSON_PUBLIC(cJSON_bool)  cJSON_IsNull(const cJSON *const item);
  CJSON_PUBLIC(cJSON_bool)  cJSON_IsNumber(const cJSON *const item);
  CJSON_PUBLIC(cJSON_bool)  cJSON_IsString(const cJSON *const item);
  CJSON_PUBLIC(cJSON_bool)  cJSON_IsArray(const cJSON *const item);
  CJSON_PUBLIC(cJSON_bool)  cJSON_IsObject(const cJSON *const item);
  CJSON_PUBLIC(cJSON_bool)  cJSON_IsRaw(const cJSON *const item);

  /* These calls create a cJSON item of the appropriate type. */
  /* 以下函式建立適當型別的 cJSON 項 */
  CJSON_PUBLIC(cJSON *)  cJSON_CreateNull(void);
  CJSON_PUBLIC(cJSON *)  cJSON_CreateTrue(void);
  CJSON_PUBLIC(cJSON *)  cJSON_CreateFalse(void);
  CJSON_PUBLIC(cJSON *)  cJSON_CreateBool(cJSON_bool boolean);
  CJSON_PUBLIC(cJSON *)  cJSON_CreateNumber(double num);
  CJSON_PUBLIC(cJSON *)  cJSON_CreateString(const char *string);
  /* raw json */
  /* 原始 JSON */
  CJSON_PUBLIC(cJSON *)  cJSON_CreateRaw(const char *raw);
  CJSON_PUBLIC(cJSON *)  cJSON_CreateArray(void);
  CJSON_PUBLIC(cJSON *)  cJSON_CreateObject(void);

  /* Create a string where valuestring references a string so
   * it will not be freed by cJSON_Delete */
  /**
   * @name      cJSON_CreateStringReference
   * @brief     建立一個字串引用項,valuestring 引用一個字串,因此不會被 cJSON_Delete 釋放
   * @param     string 字串
   * @return    cJSON* 建立的字串引用項
   */
  CJSON_PUBLIC(cJSON *)  cJSON_CreateStringReference(const char *string);
  /* Create an object/array that only references it's elements so
   * they will not be freed by cJSON_Delete */
  /**
   * @name      cJSON_CreateObjectReference
   * @brief     建立一個物件引用項,引用其元素,因此不會被 cJSON_Delete 釋放
   * @param     child 子物件
   * @return    cJSON* 建立的物件引用項
   */
  CJSON_PUBLIC(cJSON *)  cJSON_CreateObjectReference(const cJSON *child);
  /**
   * @name      cJSON_CreateArrayReference
   * @brief     建立一個陣列引用項,引用其元素,因此不會被 cJSON_Delete 釋放
   * @param     child 子陣列
   * @return    cJSON* 建立的陣列引用項
   */
  CJSON_PUBLIC(cJSON *)  cJSON_CreateArrayReference(const cJSON *child);

  /* These utilities create an Array of count items.
   * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
  /**
   * @name      cJSON_CreateIntArray
   * @brief     建立一個包含整數陣列的 cJSON 項
   * @param     numbers 整數陣列
   * @param     count 陣列元素數量
   * @return    cJSON* 建立的整數陣列項
   * @note      引數 count 不能大於整數陣列的元素數量,否則陣列訪問將越界
   */
  CJSON_PUBLIC(cJSON *)  cJSON_CreateIntArray(const int *numbers, int count);
  /**
   * @name      cJSON_CreateFloatArray
   * @brief     建立一個包含浮點陣列的 cJSON 項
   * @param     numbers 浮點陣列
   * @param     count 陣列元素數量
   * @return    cJSON* 建立的浮點陣列項
   * @note      引數 count 不能大於浮點陣列的元素數量,否則陣列訪問將越界
   */
  CJSON_PUBLIC(cJSON *)  cJSON_CreateFloatArray(const float *numbers, int count);
  /**
   * @name      cJSON_CreateDoubleArray
   * @brief     建立一個包含雙精度陣列的 cJSON 項
   * @param     numbers 雙精度陣列
   * @param     count 陣列元素數量
   * @return    cJSON* 建立的雙精度陣列項
   * @note      引數 count 不能大於雙精度陣列的元素數量,否則陣列訪問將越界
   */
  CJSON_PUBLIC(cJSON *)  cJSON_CreateDoubleArray(const double *numbers, int count);
  /**
   * @name      cJSON_CreateStringArray
   * @brief     建立一個包含字串陣列的 cJSON 項
   * @param     strings 字串陣列
   * @param     count 陣列元素數量
   * @return    cJSON* 建立的字串陣列項
   * @note
   *
   */
  CJSON_PUBLIC(cJSON *)  cJSON_CreateStringArray(const char *const *strings, int count);

  /* Append item to the specified array/object. */
  /**
   * @name      cJSON_AddItemToArray
   * @brief     將項新增到指定的陣列中
   * @param     array cJSON 陣列
   * @param     item 要新增的項
   * @return    cJSON_bool 成功返回 1,失敗返回 0
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_AddItemToArray(cJSON *array, cJSON *item);
  /*@name cJSON_AddItemToObject
   *@brief 將項新增到指定的物件中
   *@param object cJSON 物件
   *@param string 項的名稱
   *@param item 要新增的項
   *@ return cJSON_bool 成功返回 1,失敗返回 0 *
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
  /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
   * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
   * writing to `item->string` */
  /**
   * @name      cJSON_AddItemToObjectCS
   * @brief     將項新增到指定的物件中,當字串是 const 時使用
   * @param     object cJSON 物件
   * @param     string 項的名稱
   * @param     item 要新增的項
   * @return    cJSON_bool 成功返回 1,失敗返回 0
   * @note      當使用此函式時,確保在寫入 `item->string` 之前始終檢查 (item->type & cJSON_StringIsConst) 是否為零
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
  /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
  /**
   * @name      cJSON_AddItemReferenceToArray
   * @brief     將項的引用新增到指定的陣列中
   * @param     array cJSON 陣列
   * @param     item 要新增的項
   * @return    cJSON_bool 成功返回 1,失敗返回 0
   * @note      使用此函式時,您希望將現有的 cJSON 新增到新的 cJSON 中,但不希望破壞現有的 cJSON
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
  /**
   * @name      cJSON_AddItemReferenceToObject
   * @brief     將項的引用新增到指定的物件中
   * @param     object cJSON 物件
   * @param     string 項的名稱
   * @param     item 要新增的項
   * @return    cJSON_bool 成功返回 1,失敗返回 0
   * @note      使用此函式時,您希望將現有的 cJSON 新增到新的 cJSON 中,但不希望破壞現有的 cJSON
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);

  /* Remove/Detach items from Arrays/Objects. */
  /**
   * @name      cJSON_DetachItemViaPointer
   * @brief     從父物件中分離指定的項
   * @param     parent 父物件
   * @param     item 要分離的項
   * @return    cJSON* 分離的項
   */
  CJSON_PUBLIC(cJSON *)  cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item);

  /**
   * @name      cJSON_DetachItemFromArray
   * @brief     從陣列中分離指定索引的項
   * @param     array cJSON 陣列
   * @param     which 索引
   * @return    cJSON* 分離的項
   */
  CJSON_PUBLIC(cJSON *)  cJSON_DetachItemFromArray(cJSON *array, int which);

  /**
   * @name      cJSON_DeleteItemFromArray
   * @brief     從陣列中刪除指定索引的項
   * @param     array cJSON 陣列
   * @param     which 索引
   */
  CJSON_PUBLIC(void)  cJSON_DeleteItemFromArray(cJSON *array, int which);
  /**
   * @name      cJSON_DetachItemFromObject
   * @brief     從物件中分離指定名稱的項(不區分大小寫)
   * @param     object cJSON 物件
   * @param     string 項的名稱
   * @return    cJSON* 分離的項
   */
  CJSON_PUBLIC(cJSON *)  cJSON_DetachItemFromObject(cJSON *object, const char *string);
  /**
   * @name      cJSON_DetachItemFromObjectCaseSensitive
   * @brief     從物件中分離指定名稱的項(區分大小寫)
   * @param     object cJSON 物件
   * @param     string 項的名稱
   * @return    cJSON* 分離的項
   */
  CJSON_PUBLIC(cJSON *)  cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
  /**
   * @name      cJSON_DeleteItemFromObject
   * @brief     從物件中刪除指定名稱的項(不區分大小寫)
   * @param     object cJSON 物件
   * @param     string 項的名稱
   */
  CJSON_PUBLIC(void)  cJSON_DeleteItemFromObject(cJSON *object, const char *string);
  /**
   * @name      cJSON_DeleteItemFromObjectCaseSensitive
   * @brief     從物件中刪除指定名稱的項(區分大小寫)
   * @param     object cJSON 物件
   * @param     string 項的名稱
   */
  CJSON_PUBLIC(void)  cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);

  /* Update array items. */
  /**
   * @name      cJSON_InsertItemInArray
   * @brief     在陣列中插入項,將現有項右移
   * @param     array cJSON 陣列
   * @param     which 插入位置的索引
   * @param     newitem 新項
   * @return    cJSON_bool 成功返回 1,失敗返回 0
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
  /**
   * @name      cJSON_ReplaceItemViaPointer
   * @brief     用新項替換父物件中的指定項
   * @param     parent 父物件
   * @param     item 要替換的項
   * @param     replacement 新項
   * @return    cJSON_bool 成功返回 1,失敗返回 0
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item, cJSON *replacement);
  /**
   * @name      cJSON_ReplaceItemInArray
   * @brief     用新項替換陣列中指定索引的項
   * @param     array cJSON 陣列
   * @param     which 索引
   * @param     newitem 新項
   * @return    cJSON_bool 成功返回 1,失敗返回 0
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
  /**
   * @name      cJSON_ReplaceItemInObject
   * @brief     用新項替換物件中指定名稱的項(不區分大小寫)
   * @param     object cJSON 物件
   * @param     string 項的名稱
   * @param     newitem 新項
   * @return    cJSON_bool 成功返回 1,失敗返回 0
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem);
  /**
   * @name      cJSON_ReplaceItemInObjectCaseSensitive
   * @brief     用新項替換物件中指定名稱的項(區分大小寫)
   * @param     object cJSON 物件
   * @param     string 項的名稱
   * @param     newitem 新項
   * @return    cJSON_bool 成功返回 1,失敗返回 0
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem);

  /* Duplicate a cJSON item */
  /**
   * @name      cJSON_Duplicate
   * @brief     複製一個 cJSON 項
   * @param     item 要複製的項
   * @param     recurse 是否遞迴複製子項
   * @return    cJSON* 複製後的項
   * @note      複製將建立一個新的、與傳遞的項相同的 cJSON 項,在新記憶體中,需要釋放。
   *            當 recurse!=0 時,它將複製連線到該項的任何子項。返回的項的 item->next 和 ->prev 指標始終為零。
   */
  CJSON_PUBLIC(cJSON *)  cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
  /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
   * need to be released. With recurse!=0, it will duplicate any children connected to the item.
   * The item->next and ->prev pointers are always zero on return from Duplicate. */
  /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
   * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
  /**
   * @name      cJSON_Compare
   * @brief     遞迴比較兩個 cJSON 項是否相等。如果 a 或 b 為 NULL 或無效,它們將被視為不相等。
   * @param     a 第一個 cJSON 項
   * @param     b 第二個 cJSON 項
   * @param     case_sensitive 是否區分大小寫
   * @return    cJSON_bool 相等返回 1,不相等返回 0
   */
  CJSON_PUBLIC(cJSON_bool)  cJSON_Compare(const cJSON *const a, const cJSON *const b, const cJSON_bool case_sensitive);

  /* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
   * The input pointer json cannot point to a read-only address area, such as a string constant,
   * but should point to a readable and writable address area. */
  /**
   * @name      cJSON_Minify
   * @brief     壓縮字串,去除字串中的空白字元(如 ' ', '\t', '\r', '\n')
   * @param     json 要壓縮的字串
   * @note      輸入指標 json 不能指向只讀地址區域,如字串常量,而應指向可讀寫的地址區域。
   */
  CJSON_PUBLIC(void)  cJSON_Minify(char *json);

  /* Helper functions for creating and adding items to an object at the same time.
   * They return the added item or NULL on failure. */

  /**
   * @name      cJSON_AddNullToObject
   * @brief     建立並新增一個空項到物件中
   * @param     object cJSON 物件
   * @param     name 項的名稱
   * @return    cJSON* 新增的項,失敗返回 NULL
   */
  CJSON_PUBLIC(cJSON *)  cJSON_AddNullToObject(cJSON *const object, const char *const name);
  /**
   * @name      cJSON_AddTrueToObject
   * @brief     建立並新增一個 true 項到物件中
   * @param     object cJSON 物件
   * @param     name 項的名稱
   * @return    cJSON* 新增的項,失敗返回 NULL
   */
  CJSON_PUBLIC(cJSON *)  cJSON_AddTrueToObject(cJSON *const object, const char *const name);
  /**
   * @name      cJSON_AddFalseToObject
   * @brief     建立並新增一個 false 項到物件中
   * @param     object cJSON 物件
   * @param     name 項的名稱
   * @return    cJSON* 新增的項,失敗返回 NULL
   */
  CJSON_PUBLIC(cJSON *)  cJSON_AddFalseToObject(cJSON *const object, const char *const name);
  /**
   * @name      cJSON_AddBoolToObject
   * @brief     建立並新增一個布林項到物件中
   * @param     object cJSON 物件
   * @param     name 項的名稱
   * @param     boolean 布林值
   * @return    cJSON* 新增的項,失敗返回 NULL
   */
  CJSON_PUBLIC(cJSON *)  cJSON_AddBoolToObject(cJSON *const object, const char *const name, const cJSON_bool boolean);
  /**
   * @name      cJSON_AddNumberToObject
   * @brief     建立並新增一個數字項到物件中
   * @param     object cJSON 物件
   * @param     name 項的名稱
   * @param     number 數值
   * @return    cJSON* 新增的項,失敗返回 NULL
   */
  CJSON_PUBLIC(cJSON *)  cJSON_AddNumberToObject(cJSON *const object, const char *const name, const double number);
  /**
   * @name      cJSON_AddStringToObject
   * @brief     建立並新增一個字串項到物件中
   * @param     object cJSON 物件
   * @param     name 項的名稱
   * @param     string 字串值
   * @return    cJSON* 新增的項,失敗返回 NULL
   */
  CJSON_PUBLIC(cJSON *)  cJSON_AddStringToObject(cJSON *const object, const char *const name, const char *const string);
  /**
   * @name      cJSON_AddRawToObject
   * @brief     建立並新增一個原始 JSON 項到物件中
   * @param     object cJSON 物件
   * @param     name 項的名稱
   * @param     raw 原始 JSON 字串
   * @return    cJSON* 新增的項,失敗返回 NULL
   */
  CJSON_PUBLIC(cJSON *)  cJSON_AddRawToObject(cJSON *const object, const char *const name, const char *const raw);

  /**
   * @name      cJSON_AddObjectToObject
   * @brief     建立並新增一個物件項到物件中
   * @param     object cJSON 物件
   * @param     name 項的名稱
   * @return    cJSON* 新增的項,失敗返回 NULL
   */
  CJSON_PUBLIC(cJSON *)  cJSON_AddObjectToObject(cJSON *const object, const char *const name);
  /**
   * @name      cJSON_AddArrayToObject
   * @brief     建立並新增一個陣列項到物件中
   * @param     object cJSON 物件
   * @param     name 項的名稱
   * @return    cJSON* 新增的項,失敗返回 NULL
   */
  CJSON_PUBLIC(cJSON *)  cJSON_AddArrayToObject(cJSON *const object, const char *const name);

/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
  /* helper for the cJSON_SetNumberValue macro */
  /**
   * @name      cJSON_SetNumberHelper
   * @brief     幫助宏 cJSON_SetNumberValue 設定數值
   * @param     object cJSON 物件
   * @param     number 數值
   * @return    double 設定後的數值
   */
  CJSON_PUBLIC(double)  cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
  /* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
  /**
   * @name      cJSON_SetValuestring
   * @brief     更改 cJSON_String 物件的 valuestring 值,僅當物件型別為 cJSON_String 時生效
   * @param     object cJSON 物件
   * @param     valuestring 新的字串值
   * @return    char* 更改後的字串
   */
  CJSON_PUBLIC(char *)  cJSON_SetValuestring(cJSON *object, const char *valuestring);

/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
#define cJSON_SetBoolValue(object, boolValue) ( \
    (object != NULL && ((object)->type & (cJSON_False | cJSON_True))) ? (object)->type = ((object)->type & (~(cJSON_False | cJSON_True))) | ((boolValue) ? cJSON_True : cJSON_False) : cJSON_Invalid)

/* Macro for iterating over an array or object */
/* */
/*  */
/**
 * 用於在陣列或物件上迭代的宏 , 用於遍歷一個cJSON陣列中的每一個元素
 * 
 * element 是當前遍歷到的cJSON元素.
 * array 是需要遍歷的cJSON陣列。
 * for 迴圈的初始化部分:element = (array != NULL) ? (array)->child : NULL,如果 array 非空,則將 element 初始化為 array 的第一個子元素,否則初始化為 NULL。
 * 迴圈的條件部分:element != NULL,只要 element 不為空,迴圈就會繼續。
 * 迴圈的迭代部分:element = element->next,將 element 更新為下一個兄弟元素。
 */
#define cJSON_ArrayForEach(element, array) for (element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)

  /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
  /**
   * @name      cJSON_malloc
   * @brief     使用已經設定的 malloc 函式分配記憶體
   * @param     size 記憶體大小
   * @return    void* 分配的記憶體指標
   */
  CJSON_PUBLIC(void *)  cJSON_malloc(size_t size);
  /**
   * @name      cJSON_free
   * @brief     使用已經設定的 free 函式釋放記憶體
   * @param     object 要釋放的記憶體指標
   */
  CJSON_PUBLIC(void)  cJSON_free(void *object);

#ifdef __cplusplus
}
#endif

#endif
// clang-format on

cJSON.c

DaveGamble/cJSON: Ultralightweight JSON parser in ANSI C (github.com) cJSON庫 基於C語言的一個開源專案

去這裡下載cJSON.c檔案及原版cJSON.h檔案.

參考連結

  • 心知服務的說明
  • 新知天氣城市列表
  • DaveGamble/cJSON: Ultralightweight JSON parser in ANSI C (github.com) cJSON庫 基於C語言的一個開源專案

測試連結:

未來天氣
https://api.seniverse.com/v3/weather/daily.json?key=你的私鑰&location=guangzhou&language=en&unit=c&start=0&days=3
實況天氣
https://api.seniverse.com/v3/weather/now.json?key=你的私鑰&location=guangzhou&language=en&unit=c

相關文章