[c]可变参数函数

devtools/2025/1/21 17:20:48/

#include <stdio.h>
#include <stdarg.h>

void logMessage(const char *pFormat, ...) {
    // 定义一个 va_list 类型的变量 args 用于存储参数信息
    va_list args;
    
    // 初始化 args 指向第一个未命名参数
    va_start(args, pFormat);
    
    // 创建一个足够大的缓冲区来保存格式化后的字符串
    char buffer[1024];
    
    // 使用 vsnprintf 格式化字符串并写入到 buffer 中
    int len = vsnprintf(buffer, sizeof(buffer), pFormat, args);
    
    if (len > -1 && len < sizeof(buffer)) {
        // 如果 vsnprintf 成功并且没有被截断,则输出结果
        printf("%s\n", buffer);
    } else {
        // 处理错误情况(例如,缓冲区太小)
        printf("Buffer too small or formatting error.\n");
    }
    
    // 清理工作
    va_end(args);
}

int main() {
    // 调用 logMessage 函数,它支持类似于 printf 的语法
    logMessage("User %s logged in from IP: %s", "Alice", "192.168.1.1");
    logMessage("Error code: %d, Message: %s", 404, "Not Found");
    
    return 0;
}

- **logMessage 函数**: 这是一个接受可变数量参数的函数,首先通过`va_start`初始化`args`,然后调用`vsnprintf`根据提供的格式化字符串和参数生成最终的消息。如果格式化成功且结果没有超出缓冲区大小限制,则使用`printf`输出结果。最后,通过`va_end`完成清理工作。

 

`vsnprintf` 是 C 标准库中的一个函数,用于格式化字符串并将其输出到一个指定的缓冲区。它与 `snprintf` 类似,但接收的是一个 `va_list` 类型的参数列表而不是直接使用省略号(...)。这使得它非常适合在实现支持可变参数列表的函数时使用。

### 函数原型

```c
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
```

### 参数解释

1. **char *str**

   目标缓冲区的指针,格式化后的字符串将被写入该缓冲区。如果 `size` 为零,则可以传递一个空指针,因为在这种情况下不会尝试写入数据,仅返回所需缓冲区大小。

2. **size_t size**

   指定目标缓冲区的最大字节数(包括结尾的空字符 `\0`)。这意味着函数最多会写入 `size - 1` 个字符到 `str` 中,并确保 `str` 以空字符结束。如果格式化后的字符串长度超过了 `size - 1`,则会被截断。

3. **const char *format**

   格式化字符串,包含文本和嵌入的格式说明符(如 `%d` 表示整数,`%s` 表示字符串等)。这些说明符将被后续提供的参数替换。

4. **va_list ap**

   这是一个指向参数列表的指针,包含了所有按照 `format` 中的说明符顺序排列的额外参数。这个参数通常通过 `va_start` 初始化,并且在调用 `vsnprintf` 后应该调用 `va_end` 来清理。

### 返回值

- 如果成功并且没有发生截断,则返回写入到 `str` 的字符数(不包括结尾的空字符)。
- 如果由于缓冲区大小不足而发生截断,则返回将会写入的字符总数(假设没有大小限制),以便你可以知道需要多大的缓冲区来存储完整的格式化字符串。
- 如果发生错误,返回负值。

### 使用场景

`vsnprintf` 常用于实现自定义的格式化输出函数,特别是那些需要处理不确定数量参数的情况。例如,构建自己的日志记录函数或调试信息打印函数时非常有用。

### 示例代码片段

以下是一个简单的例子,演示了如何使用 `vsnprintf`:

```c
#include <stdio.h>
#include <stdarg.h>

void logMessage(const char *format, ...) {
    char buffer[1024];
    va_list args;
    
    va_start(args, format);
    int len = vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args);
    
    if (len > -1 && len < sizeof(buffer)) {
        printf("%s\n", buffer);
    } else {
        printf("Error: Buffer too small or formatting error.\n");
    }
}

int main() {
    logMessage("User %s logged in from IP: %s", "Alice", "192.168.1.1");
    logMessage("Error code: %d, Message: %s", 404, "Not Found");
    return 0;
}
```


http://www.ppmy.cn/devtools/152386.html

相关文章

嵌入式知识点总结 C/C++ 专题提升(一)-关键字

针对于嵌入式软件杂乱的知识点总结起来&#xff0c;提供给读者学习复习对下述内容的强化。 目录 1.C语言宏中"#“和"##"的用法 1.1.(#)字符串化操作符 1.2.(##)符号连接操作符 2.关键字volatile有什么含意?并举出三个不同的例子? 2.1.并行设备的硬件寄存…

大模型学习笔记 - 第一期 - Milvus向量数据库

大模型学习笔记 - 向量数据库 目录 大模型学习笔记 - 向量数据库传统文字检索(无嵌入)面临的困境1. 用户和商户表述差异2. 不同语种的表述差异3. 不同背景下的音译表述差异 向量检索向量化服务 参考 传统文字检索(无嵌入)面临的困境 1. 用户和商户表述差异 ​ 如果商户维护了…

在 Web 应用中集成多种地图 API 的实现与管理

在 Web 开发中&#xff0c;集成地图服务是常见的需求之一&#xff0c;尤其是在需要定位、路线规划或展示地理信息的应用中。常见的地图 API 服务包括百度地图、谷歌地图和雅虎地图等。在这篇文章中&#xff0c;我们将深入探讨如何在 Web 应用中同时集成多个地图 API&#xff0c…

Windows电脑安装USB Redirector并实现内外网跨网USB共享通信访问

文章目录 前言1. 安装下载软件1.1 内网安装使用USB Redirector1.2 下载安装cpolar内网穿透 2. 完成USB Redirector服务端和客户端映射连接3. 设置固定的公网地址 前言 我们每天都在与各种智能设备打交道&#xff0c;从手机到电脑&#xff0c;再到各种外设&#xff0c;它们已经…

全自动化河道水位监测系统:实时传输与远程监控

全自动化河道水位监测系统是利用先进的自动化技术和智能化设备&#xff0c;实现河道水位的实时监测、数据采集、处理分析、传输与远程监控的一体化解决方案。该系统的设计目标是确保河道水位监测的精准性和及时性&#xff0c;为防洪抗旱、水资源管理及环境保护等提供科学的数据…

LeetCode hot 力扣100 LRU 缓存

splice 是 C STL 的 std::list 提供的一个成员函数&#xff0c;用于高效地将一个或多个元素从一个链表移动到另一个链表&#xff0c;或在同一链表内重新排列元素。它不涉及数据的拷贝&#xff0c;而是直接修改链表节点的指针&#xff0c;因此操作非常高效。splice 的功能splice…

windows下使用docker执行器并配置 hosts 解析

本篇目录 1. 问题背景2. 环境准备2.1 云上开通windows 2022 英文版机器2.1.1 安装 git2.1.2 安装 runner2.1.3 装docker2.1.4 注册runner并使用docker执行器 3. 项目信息3.1 编写window bat脚本3.2 项目.gitlab-ci.yml文件 4. 测试结论4.1 运行流水线 5. troubleshooting问题1&…

Vue2:el-tree用scope slot为每一个节点添加一个鼠标悬浮时出现的右对齐的按钮

el-tree中,每一个节点后面添加一个按钮,响应除节点点击事件之外的操作,要求: 1、按钮在鼠标悬浮在该节点之上时才出现 2、按钮右对齐 实现如下。 1、为每个节点添加按钮 从官网说明来看,有两种方式添加按钮,render-content和 scoped slot,我使用的是scoped slot方式…