首页 后端开发 C++ 使用 C 语言 API:现代开发人员的实用指南

使用 C 语言 API:现代开发人员的实用指南

Nov 24, 2024 am 08:10 AM

Consuming APIs in C: a practical guide for modern developers

如今,使用 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/curl.h>

// 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 的内部逻辑。
回调必须累积块,最终重建完整的响应。

这是一个示例序列:

  1. 服务器开始发送响应。
  2. libcurl 接收第一个块并调用回调。
  3. 回调处理或存储块。
  4. libcurl 接收下一个块并再次调用回调。
  5. 此过程将继续,直到收到完整的回复。

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/curl.h>

// 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中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

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

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

C语言数据结构:树和图的数据表示与操作 C语言数据结构:树和图的数据表示与操作 Apr 04, 2025 am 11:18 AM

C语言数据结构:树和图的数据表示与操作树是一个层次结构的数据结构由节点组成,每个节点包含一个数据元素和指向其子节点的指针二叉树是一种特殊类型的树,其中每个节点最多有两个子节点数据表示structTreeNode{intdata;structTreeNode*left;structTreeNode*right;};操作创建树遍历树(先序、中序、后序)搜索树插入节点删除节点图是一个集合的数据结构,其中的元素是顶点,它们通过边连接在一起边可以是带权或无权的数据表示邻

C语言文件操作难题的幕后真相 C语言文件操作难题的幕后真相 Apr 04, 2025 am 11:24 AM

文件操作难题的真相:文件打开失败:权限不足、路径错误、文件被占用。数据写入失败:缓冲区已满、文件不可写、磁盘空间不足。其他常见问题:文件遍历缓慢、文本文件编码不正确、二进制文件读取错误。

c语言函数的基本要求有哪些 c语言函数的基本要求有哪些 Apr 03, 2025 pm 10:06 PM

C语言函数是代码模块化和程序搭建的基础。它们由声明(函数头)和定义(函数体)组成。C语言默认使用值传递参数,但也可使用地址传递修改外部变量。函数可以有返回值或无返回值,返回值类型必须与声明一致。函数命名应清晰易懂,使用驼峰或下划线命名法。遵循单一职责原则,保持函数简洁性,以提高可维护性和可读性。

c上标3下标5怎么算 c上标3下标5算法教程 c上标3下标5怎么算 c上标3下标5算法教程 Apr 03, 2025 pm 10:33 PM

C35 的计算本质上是组合数学,代表从 5 个元素中选择 3 个的组合数,其计算公式为 C53 = 5! / (3! * 2!),可通过循环避免直接计算阶乘以提高效率和避免溢出。另外,理解组合的本质和掌握高效的计算方法对于解决概率统计、密码学、算法设计等领域的许多问题至关重要。

c语言函数名定义 c语言函数名定义 Apr 03, 2025 pm 10:03 PM

C语言函数名定义包括:返回值类型、函数名、参数列表和函数体。函数名应清晰、简洁、统一风格,避免与关键字冲突。函数名具有作用域,可在声明后使用。函数指针允许将函数作为参数传递或赋值。常见错误包括命名冲突、参数类型不匹配和未声明的函数。性能优化重点在函数设计和实现上,而清晰、易读的代码至关重要。

c语言函数的概念 c语言函数的概念 Apr 03, 2025 pm 10:09 PM

C语言函数是可重复利用的代码块,它接收输入,执行操作,返回结果,可将代码模块化提高可复用性,降低复杂度。函数内部机制包含参数传递、函数执行、返回值,整个过程涉及优化如函数内联。编写好的函数遵循单一职责原则、参数数量少、命名规范、错误处理。指针与函数结合能实现更强大的功能,如修改外部变量值。函数指针将函数作为参数传递或存储地址,用于实现动态调用函数。理解函数特性和技巧是编写高效、可维护、易理解的C语言程序的关键。

CS-第 3 周 CS-第 3 周 Apr 04, 2025 am 06:06 AM

算法是解决问题的指令集,其执行速度和内存占用各不相同。编程中,许多算法都基于数据搜索和排序。本文将介绍几种数据检索和排序算法。线性搜索假设有一个数组[20,500,10,5,100,1,50],需要查找数字50。线性搜索算法会逐个检查数组中的每个元素,直到找到目标值或遍历完整个数组。算法流程图如下:线性搜索的伪代码如下:检查每个元素:如果找到目标值:返回true返回falseC语言实现:#include#includeintmain(void){i

C语言多线程编程:新手指南与疑难解答 C语言多线程编程:新手指南与疑难解答 Apr 04, 2025 am 10:15 AM

C语言多线程编程指南:创建线程:使用pthread_create()函数,指定线程ID、属性和线程函数。线程同步:通过互斥锁、信号量和条件变量防止数据竞争。实战案例:使用多线程计算斐波那契数,将任务分配给多个线程并同步结果。疑难解答:解决程序崩溃、线程停止响应和性能瓶颈等问题。

See all articles