如今,使用 Web API 是在应用程序之间交换数据的常见做法。关于使用 JavaScript、Python 或 PHP 等语言的 API 的教程有很多,但 C(通常与系统级编程相关)很少被考虑用于此目的。然而,C 完全有能力处理 API 请求,使其成为销售点 (PoS) 系统、物联网设备或嵌入式应用程序等场景的可行选择,在这些场景中,C 已经因其效率和低级控制而被使用。
本文探讨了如何利用 libcurl 库使用 C 语言的 API。最后,您将了解如何使用 C 从 API 获取和处理数据,以及为什么这种方法即使在现代开发中也有意义。
为什么使用 C 来使用 API?
虽然高级语言主导 Web 开发,但 C 仍然是在特定用例中使用 API 的实用选择:
- 性能:C 提供高性能和最小的开销,使其适合物联网设备等资源受限的环境。
- 控制:直接内存管理允许微调优化,特别是对于嵌入式系统。
- 互操作性:C 的广泛使用意味着它可以与系统级操作很好地集成,例如控制硬件、传感器或其他外设。
- 寿命长:用 C 语言构建的应用程序通常具有很长的寿命,尤其是在零售或制造等行业。
libcurl 简介:C 语言 HTTP 工具
要使用 C 语言的 API,libcurl 是首选库。它是一个开源、可移植且功能丰富的库,用于处理通过 HTTP、HTTPS、FTP 等的网络请求。它支持:
- 发出 GET、POST 和其他 HTTP 请求。
- 处理标头和身份验证。
- 高效处理回复。
使用 C 语言 API 的基本步骤
让我们逐步了解使用 C 语言使用 API 的过程,重点关注获取 JSON 数据的实际示例。
设置和安装
要使用 libcurl,您需要在系统上安装它。对于大多数 Linux 发行版,这可以通过以下方式完成:
sudo apt-get install libcurl4-openssl-dev
在 Windows 上,您可以从 libcurl 网站下载预编译的二进制文件:https://curl.se/download.html
在 macOS 上,如果您使用 Homebrew,可以通过
安装它
brew install curl
构建你的 C 程序
从 API 获取数据的简单 C 程序涉及以下组件:
- 正在初始化 libcurl。
- 配置 API 请求(URL、HTTP 方法、标头等)。
- 接收并存储响应。
- 清理资源。
这是一个从公共 API 获取 JSON 数据的示例程序:
sudo apt-get install libcurl4-openssl-dev
运行步骤
将代码保存在文件中,例如 get.c。
使用以下命令编译它:
brew install curl
运行编译好的程序:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <curl> // Struct to hold response data struct Memory { char *response; size_t size; }; // Callback function to handle the data received from the API static size_t ResponseCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t totalSize = size * nmemb; struct Memory *mem = (struct Memory *)userp; printf(". %zu %zu\n", size, nmemb); char *ptr = realloc(mem->response, mem->size + totalSize + 1); if (ptr == NULL) { printf("Not enough memory to allocate buffer.\n"); return 0; } mem->response = ptr; memcpy(&(mem->response[mem->size]), contents, totalSize); mem->size += totalSize; mem->response[mem->size] = '<pre class="brush:php;toolbar:false">gcc get.c -o get -lcurl'; return totalSize; } int main() { CURL *curl; CURLcode res; struct Memory chunk; chunk.response = malloc(1); // Initialize memory chunk.size = 0; // No data yet curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { // Set URL of the API endpoint char access_token[] = "your-access-token"; char slug[] = "home"; char version[]= "draft"; char url[256]; snprintf(url, sizeof(url), "https://api.storyblok.com/v2/cdn/stories/%s?version=%s&token=%s", slug, version, access_token); // Print the URL printf("URL: %s\n", url); // initializing libcurl // setting the URL curl_easy_setopt(curl, CURLOPT_URL, url ); // Follow redirect curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // Set callback function to handle response data curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ResponseCallback); // Pass the Memory struct to the callback function curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); // Perform the HTTP GET request res = curl_easy_perform(curl); // Check for errors if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } else { printf("Response data size: %zu\n", chunk.size); //printf("Response data: \n%s\n", chunk.response); } // Cleanup curl_easy_cleanup(curl); } // Free allocated memory free(chunk.response); curl_global_cleanup(); return 0; }
使用 libcurl 了解 HTTP 响应中的回调机制
在 C 中使用 libcurl 处理 HTTP 响应时,了解回调函数的行为非常重要。您定义的用于处理响应数据的回调函数(例如 ResponseCallback 函数)可能会针对单个 HTTP 响应调用多次。这就是为什么以及它是如何工作的。
为什么回调会被多次调用?
libcurl 中的回调机制旨在高效、灵活地处理数据。 libcurl 不会在处理整个响应之前等待下载整个响应,而是以较小的块处理响应,并在收到每个块时调用回调函数。
此行为允许:
- 高效的内存使用:通过增量处理块,您无需为整个响应预先分配大块内存。
- 流式处理:您可以在每个块到达时对其进行处理或操作,这对于流式传输大型响应或实时处理数据非常有用。
它是如何工作的?
每次从服务器接收到一块数据时,libcurl 都会调用您的回调函数。每个块的大小取决于网络条件、缓冲区大小和 libcurl 的内部逻辑。
回调必须累积块,最终重建完整的响应。
这是一个示例序列:
- 服务器开始发送响应。
- libcurl 接收第一个块并调用回调。
- 回调处理或存储块。
- libcurl 接收下一个块并再次调用回调。
- 此过程将继续,直到收到完整的回复。
ResponseCallback 函数的分步源代码解释
ResponseCallback 是 libcurl 接收数据时调用的函数。
函数声明
sudo apt-get install libcurl4-openssl-dev
- void *contents:这是指向从服务器接收的数据的指针。 libcurl 提供了这个缓冲区并用它下载的数据填充它。
- size_t size 和 size_t nmemb:这些表示每个内存块的大小(size)和块的数量(nmemb)。 size * nmemb 共同给出了该块中接收到的数据的总大小。
- void *userp:这是通过curl_easy_setopt(curl, CURLOPT_WRITEDATA, ...)传递给回调函数的用户定义指针。在此示例中,它是指向 struct Memory 对象的指针,该对象存储完整的响应。
计算总数据大小
brew install curl
通过将一个块的大小 (size) 乘以块的数量 (nmemb) 来计算当前接收到的数据块的总大小。
例如,如果服务器发送 8 个块,每个块 256 字节,totalSize 将为 8 * 256 = 2048 字节。
访问用户数据(struct Memory)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <curl> // Struct to hold response data struct Memory { char *response; size_t size; }; // Callback function to handle the data received from the API static size_t ResponseCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t totalSize = size * nmemb; struct Memory *mem = (struct Memory *)userp; printf(". %zu %zu\n", size, nmemb); char *ptr = realloc(mem->response, mem->size + totalSize + 1); if (ptr == NULL) { printf("Not enough memory to allocate buffer.\n"); return 0; } mem->response = ptr; memcpy(&(mem->response[mem->size]), contents, totalSize); mem->size += totalSize; mem->response[mem->size] = '<pre class="brush:php;toolbar:false">gcc get.c -o get -lcurl'; return totalSize; } int main() { CURL *curl; CURLcode res; struct Memory chunk; chunk.response = malloc(1); // Initialize memory chunk.size = 0; // No data yet curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { // Set URL of the API endpoint char access_token[] = "your-access-token"; char slug[] = "home"; char version[]= "draft"; char url[256]; snprintf(url, sizeof(url), "https://api.storyblok.com/v2/cdn/stories/%s?version=%s&token=%s", slug, version, access_token); // Print the URL printf("URL: %s\n", url); // initializing libcurl // setting the URL curl_easy_setopt(curl, CURLOPT_URL, url ); // Follow redirect curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // Set callback function to handle response data curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ResponseCallback); // Pass the Memory struct to the callback function curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); // Perform the HTTP GET request res = curl_easy_perform(curl); // Check for errors if (res != CURLE_OK) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } else { printf("Response data size: %zu\n", chunk.size); //printf("Response data: \n%s\n", chunk.response); } // Cleanup curl_easy_cleanup(curl); } // Free allocated memory free(chunk.response); curl_global_cleanup(); return 0; }
userp 指针被转换为 struct Memory *。该结构体已在主程序中前面传递,用于累积接收到的数据。
结构体 Memory 定义为:
./get
- 响应:动态分配的字符串,用于存储下载的数据。
- size:响应字符串的当前大小。
重新分配内存
static size_t ResponseCallback(void *contents, size_t size, size_t nmemb, void *userp)
调整响应缓冲区的大小以容纳新的数据块:
- mem->size:缓冲区的当前大小。
- TotalSize:新块的大小。
- 1: 空终止符 ( ) 的空格使其成为有效的 C 字符串。
- realloc:为响应缓冲区动态重新分配内存。
如果分配失败,realloc返回NULL,旧内存仍然有效。
处理内存分配错误
size_t totalSize = size * nmemb;
如果内存分配失败(因此 ptr 为 NULL),则打印错误消息并返回 0。返回 0 表示 libcurl 中止传输。
更新缓冲区
struct Memory *mem = (struct Memory *)userp;
- mem->response = ptr:将新分配的内存分配回响应指针。
-
memcpy:将新的数据块从内容复制到缓冲区中:
- &(mem->response[mem->size]):缓冲区中应附加新数据的位置(当前数据的末尾)。
- content: 从服务器接收到的数据。
- TotalSize:要复制的数据的大小。
更新总大小
struct Memory { char *response; size_t size; };
增加响应缓冲区的大小以反映附加新块后的新总大小。
Null-终止响应字符串
sudo apt-get install libcurl4-openssl-dev
在响应缓冲区末尾添加一个空终止符,使其成为有效的 C 字符串。
这确保了响应可以被安全地视为常规的空终止字符串。
返回总大小
brew install curl
返回已处理的字节数(totalSize)。
这向 libcurl 发出信号,表明数据块已成功处理。
何时为 API 选择 C
在以下情况下使用 C 来使用 API:
- 性能很重要:C 是速度关键型应用的理想选择。
- 系统集成:您需要将网络请求与硬件操作结合起来(例如,为 PoS 系统获取数据)。
- 嵌入式系统:资源受限的设备受益于 C 语言的效率。
- 好奇心和探索:有时,您使用 C 只是因为您喜欢编程,并且想通过探索较低级语言来完成通常为高级语言保留的任务来挑战自己。这是加深您对事物底层工作原理的理解的好方法!
结论
在当今的高级编程世界中,使用 C 语言的 API 似乎不合常规,但对于需要性能、控制以及与系统级操作集成的场景来说,它是一个强大的工具。通过使用 libcurl 等库,开发人员可以轻松地将 HTTP 请求集成到 C 应用程序中,从而弥合现代 API 和传统系统级编程之间的差距。
有了这些知识,您就可以构建与 API 无缝交互的 C 应用程序,证明 C 即使在现代开发工作流程中仍然具有相关性。
以上是使用 C 语言 API:现代开发人员的实用指南的详细内容。更多信息请关注PHP中文网其他相关文章!

C 在现代世界中的应用广泛且重要。1)在游戏开发中,C 因其高性能和多态性被广泛使用,如UnrealEngine和Unity。2)在金融交易系统中,C 的低延迟和高吞吐量使其成为首选,适用于高频交易和实时数据分析。

C 中有四种常用的XML库:TinyXML-2、PugiXML、Xerces-C 和RapidXML。1.TinyXML-2适合资源有限的环境,轻量但功能有限。2.PugiXML快速且支持XPath查询,适用于复杂XML结构。3.Xerces-C 功能强大,支持DOM和SAX解析,适用于复杂处理。4.RapidXML专注于性能,解析速度极快,但不支持XPath查询。

C 通过第三方库(如TinyXML、Pugixml、Xerces-C )与XML交互。1)使用库解析XML文件,将其转换为C 可处理的数据结构。2)生成XML时,将C 数据结构转换为XML格式。3)在实际应用中,XML常用于配置文件和数据交换,提升开发效率。

C#和C 的主要区别在于语法、性能和应用场景。1)C#语法更简洁,支持垃圾回收,适用于.NET框架开发。2)C 性能更高,需手动管理内存,常用于系统编程和游戏开发。

C#和C 的历史与演变各有特色,未来前景也不同。1.C 由BjarneStroustrup在1983年发明,旨在将面向对象编程引入C语言,其演变历程包括多次标准化,如C 11引入auto关键字和lambda表达式,C 20引入概念和协程,未来将专注于性能和系统级编程。2.C#由微软在2000年发布,结合C 和Java的优点,其演变注重简洁性和生产力,如C#2.0引入泛型,C#5.0引入异步编程,未来将专注于开发者的生产力和云计算。

C#和C 的学习曲线和开发者体验有显着差异。 1)C#的学习曲线较平缓,适合快速开发和企业级应用。 2)C 的学习曲线较陡峭,适用于高性能和低级控制的场景。

C#和C 在面向对象编程(OOP)中的实现方式和特性上有显着差异。 1)C#的类定义和语法更为简洁,支持如LINQ等高级特性。 2)C 提供更细粒度的控制,适用于系统编程和高性能需求。两者各有优势,选择应基于具体应用场景。

从XML转换到C 并进行数据操作可以通过以下步骤实现:1)使用tinyxml2库解析XML文件,2)将数据映射到C 的数据结构中,3)使用C 标准库如std::vector进行数据操作。通过这些步骤,可以高效地处理和操作从XML转换过来的数据。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

SublimeText3 Linux新版
SublimeText3 Linux最新版

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

Dreamweaver Mac版
视觉化网页开发工具

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中