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