当前位置: 首页 > news >正文

C++之va_start、vasprintf、va_end应用总结(二百二十六)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

1.前言

本篇目的:C++之va_start、vasprintf、va_end应用总结。

在C/C++语言中,va_startvasprintfva_end是与可变参数相关的函数。它们通常与stdarg.h头文件一起使用。

  1. va_start函数:

    • va_start函数用于初始化可变参数列表。它接受两个参数:第一个参数是一个va_list类型的变量,第二个参数是最后一个固定参数的前一个参数的名称。
    • 这个函数将va_list类型变量初始化为指向可变参数列表的起始位置。
  2. vasprintf函数:

    • vasprintf函数用于将格式化的可变参数输出到动态分配的字符串中。
    • 它接受两个参数:第一个参数是一个指向char指针的指针,第二个参数是一个格式化字符串。
    • 这个函数会根据格式化字符串和可变参数列表生成一个动态分配的字符串,并将指针保存在第一个参数所指向的位置。
  3. va_end函数:

    • va_end函数用于结束可变参数的获取。
    • 它接受一个参数,即一个va_list类型的变量。
    • 这个函数对可变参数列表进行清理,使其无法再被访问。

通常在需要处理可变参数的情况下,使用实现Printf风格的函数或者处理命令行参数时。

2.应用实例

<1>.v1.0

#include <stdio.h>
#include <stdarg.h>void sum(int count, ...)
{va_list args;int total = 0;// 初始化可变参数列表va_start(args, count);// 遍历可变参数列表并求和for (int i = 0; i < count; i++){int num = va_arg(args, int);total += num;}// 结束可变参数列表va_end(args);printf("Sum: %d\n", total);
}int main()
{sum(3, 1, 2, 3);  // 输出 Sum: 6return 0;
}

va_start是一个宏,用于处理可变参数列表。它的原理是基于C语言的可变参数机制。

va_start宏的工作原理如下:

  1. 首先,通过传入的参数列表的类型信息和格式化字符串来确定参数列表的起始位置。

  2. 然后,通过指针运算和类型大小来计算出参数列表中各个参数的位置。

  3. 最后,将参数列表位置信息保存在一个va_list类型的变量中,供后续函数进行处理。

va_start宏的实现通常依赖于编译器和操作系统的底层支持。它使用了一些机制来获取参数列表的信息,如栈帧结构、类型信息、指针运算等。

具体实现的细节可能因编译器和操作系统而异,但通常会涉及以下步骤:

  1. 获取栈帧指针:va_start宏需要通过访问栈来获取参数列表的位置信息。它首先获取当前函数的栈帧指针,可以通过编译器提供的相关函数或底层汇编指令来实现。

  2. 计算参数列表位置:通过栈帧指针和参数类型大小,va_start宏可以计算出参数列表中各个参数的位置。这通常涉及指针运算,根据参数类型大小来移动指针位置。

  3. 保存参数列表信息:va_start宏将参数列表位置信息保存在一个va_list类型的变量中,以便后续的函数进行处理。可以将栈帧指针和计算得到的参数列表位置信息存储在va_list变量中。

va_start宏使用一些编译器和操作系统提供的底层机制来实现可变参数的处理。具体实现可能会因编译器和操作系统的不同而异,也可能受到编译器的优化策略的影响。

<2>.v2.0

#include <stdio.h>
#include <stdarg.h>char* format_string(const char* format, ...)
{va_list args;char* str;// 初始化可变参数列表va_start(args, format);// 格式化字符串并存储到动态分配的字符串中int length = vasprintf(&str, format, args);// 结束可变参数列表va_end(args);printf("Formatted String: %s\n", str);printf("String Length: %d\n", length);return str;
}int main()
{char* result = format_string("Hello %s, your age is %d.", "John", 25);// 输出 Formatted String: Hello John, your age is 25.// 输出 String Length: 30free(result);  // 释放动态分配的字符串return 0;
}

va_end是一个宏,用于结束对可变参数列表的访问。它的原理是基于C语言的可变参数机制。

va_end宏的工作原理如下:

  1. 首先,它接收一个va_list类型的变量作为参数,该变量保存了参数列表的位置信息。

  2. 接着,通过一系列机制(如编译器和操作系统的底层支持)实现将参数列表进行清理和释放的操作。

  3. 最后,将va_list类型的变量标记为无效,以确保之后对它的访问是无效的。

具体实现的细节可能因编译器和操作系统而异,但通常会涉及以下步骤:

  1. 清理参数列表:va_end宏根据参数列表的位置信息,使用特定的机制将参数列表进行清理。它可能涉及释放资源、清理栈上的参数值等操作。具体的清理操作由编译器和操作系统提供的底层支持来实现。

  2. 使va_list变量失效:为了确保在之后对va_list变量的访问是无效的,va_end宏将该变量标记为无效。这样可以避免误用已经结束的参数列表。

va_end宏的实现依赖于编译器和操作系统的底层支持。具体实现的细节可能会因编译器和操作系统的不同而异。但无论实现细节如何,va_end宏的目标都是确保正确清理和释放可变参数列表所占用的资源,并将va_list变量标记为无效。

<3>.v3.0

#include <iostream>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <string>using namespace std;string AStringPrintf(const char *format, ...) {va_list ap;va_start(ap, format);char *buffer;int bufferSize = vasprintf(&buffer, format, ap);va_end(ap);if(bufferSize < 0) {return string();}string result(buffer);free(buffer);buffer = NULL;return result;
}int main(){char str[64]={1,2,3,5,6,7,8,9};string buf =  AStringPrintf(str);printf("buf = %s\n",buf.c_str());
}
  1. vsnprintf函数接收一个格式化字符串和一个va_list类型的参数列表。利用格式化字符串,它将参数列表中的数据转换为相应的字符串格式。

  2. 首先,vsnprintf函数根据格式化字符串中的格式指示符,逐个读取参数列表的值,并根据指示符的要求对其进行格式化。

  3. 然后,vsnprintf函数根据格式化的结果,将其写入到指定的缓冲区中。它会确保写入的数据不超过指定的缓冲区大小。

  4. 最后,vsnprintf函数会在写入完成后,返回实际写入的字符数(不包括结尾的’\0’)。如果缓冲区大小不足以容纳格式化后的字符串,vsnprintf函数会截断字符串,但仍然会返回实际要写入的字符数。

需要注意的是,由于vsnprintf函数是经过格式化而得到的字符串的长度是不确定的,因此在使用之前需要分配足够的缓冲区来存储格式化后的字符串,以避免缓冲区溢出的情况发生。

vsnprintf函数是一个用于以固定格式将可变参数格式化为字符串的函数。它将格式化的结果写入指定的缓冲区,并返回实际写入的字符数。这个函数在C++中可用于处理可变参数,并将其转换为字符串格式。

<4>.v4.0

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>void dynamic_print(const char* format, ...)
{va_list args;va_start(args, format);char* dyn_str = NULL;size_t str_length = 0;// 计算动态生成字符串所需的长度str_length = vsnprintf(NULL, 0, format, args);// 为字符串动态分配内存dyn_str = (char*)malloc(str_length + 1);// 动态生成字符串vsnprintf(dyn_str, str_length + 1, format, args);printf("%s", dyn_str);free(dyn_str);va_end(args);
}int main(){int num1 = 10;int num2 = 20;dynamic_print("Sum: %d + %d = %d\n", num1, num2, num1 + num2);return 0;
}

相关文章:

C++之va_start、vasprintf、va_end应用总结(二百二十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…...

OpenCV自学笔记十一:形态学操作(一)

目录 1、腐蚀 2、膨胀 3、通用形态学函数 4、开运算 5、闭运算 1、腐蚀 腐蚀&#xff08;Erosion&#xff09;是数字图像处理中的一种形态学操作&#xff0c;用于消除图像中边界附近的细小区域或缩小对象的大小。腐蚀操作通过卷积输入图像与结构元素&#xff08;也称为腐…...

封装全局异常处理

文章目录 1 定义错误码类2 定义业务异常类3 全局异常处理器4 使用5 前端请求效果总结 1 定义错误码类 ​ 可以定义各种错误码枚举&#xff0c;比如业务&#xff0c;系统相关的报错信息 /*** 错误代码* 错误码** author leovany* date 2023/09/23*/ public enum ErrorCode {SU…...

python的requests响应请求,结果乱码,即使设置了response.encoding也没有用的解决方法

一、问题 如图&#xff1a; 一般出现乱码&#xff0c;我们会有三种解决方式&#xff0c;如下但是图中解决了发现还是不行, response.encodingresponse.apparent_encoding通过看网页源码对response.encodingutf8指定编码格式或者直接通过response.content.decode()来获得源码 出…...

PyCharm 手动下载插件

插件模块一直加载失败&#xff0c;报错信息&#xff1a; Marketplace plugins are not loaded. Check the internet connection and refresh. 尝试了以下方法&#xff0c;均告失败&#xff1a; pip 换源Manage Plugin Repositories...HTTP 代理设置...关闭三个防火墙 最后选…...

Gnomon绑定基础(约束 IK 节点)

点约束 方向约束 父约束 目标约束 修改后 对象方向 IK控制柄 直的骨骼&#xff0c;指定IK怎么弯曲 直的骨骼&#xff0c;指定IK怎么弯曲 样条曲线 数学节点 乘除节点 混合节点 注意...

STL常用遍历,查找,算法

目录 1.遍历算法 1.1for_earch 1.2transform 2.常用查找算法 2.1find&#xff0c;返回值是迭代器 2.1.1查找内置数据类型 2.1.2查找自定义数据类型 2.2fin_if 按条件查找元素 2.2.1查找内置的数据类型 2.2.2查找内置数据类型 2.3查找相邻元素adjeacent_find 2.4查找指…...

BCC源码内容概览(1)

接前一篇文章&#xff1a;BCC源码编译和安装 本文参考官网中的Contents部分的介绍。 BCC源码根目录的文件&#xff0c;其中一些是同时包含C和Python的单个文件&#xff0c;另一些是.c和.py的成对文件&#xff0c;还有一些是目录。 跟踪&#xff08;Tracing&#xff09; exam…...

mysql限制用户登录失败次数,限制时间

mysql用户登录限制设置 mysql 需要进行用户登录次数限制,当使用密码登录超过 3 次认证链接失败之后,登录锁住一段时间,禁止登录这里使用的 mysql: 8.1.0 这种方式不用重启数据库. 配置: 首先进入到 mysql 命令行:然后需要安装两个插件: 在 mysql 命令行中执行: mysql> INS…...

从利用Arthas排查线上Fastjson问题到Java动态字节码技术(下)

上一篇从Arthas的源码引出了Java动态字节码技术&#xff0c;那么这一篇就从几种Java字节码技术出发&#xff0c;看看Arthas是如何通过动态字节码技术做到无侵入的源码增强&#xff1b; Java大部分情况下都是解释执行的&#xff0c;也就是解释.class文件&#xff0c;所以如果我们…...

Ubuntu中安装Anaconda 如何将 路径导入为全局变量

第一步&#xff1a;将你的anaconda 路径复制下来&#xff0c;在终端输入对应路径。 echo export PATH"/home/你的用户名/anaconda3/bin:$PATH" >> ~/.bashrc 第二步&#xff1a;在终端输入下面命令或者重启系统。 source ~/.bashrc 在对应的anaconda安装目…...

【QT】Qt的随身笔记(持续更新...)

目录 Qt 获取当前电脑桌面的路径Qt 获取当前程序运行路径Qt 创建新的文本文件txt&#xff0c;并写入内容如何向QPlainTextEdit 写入内容QTimerQMessageBox的使用QLatin1StringQLayoutC在c头文件中写#include类的头文件与直接写class加类名有何区别mutable关键字前向声明 QFontQ…...

【LeetCode-简单题】589. N 叉树的前序遍历

文章目录 题目方法一&#xff1a;单循环栈做法方法二&#xff1a;递归 题目 方法一&#xff1a;单循环栈做法 关键在于子节点的入栈顺序&#xff0c;决定了子节点的出栈顺序&#xff0c; 因为是前序遍历 所以压栈顺序先让右边的入栈 依次往左 这样左边的节点会在栈顶 这样下次…...

Linphone3.5.2 ARM RV1109音视频对讲开发记录

Linphone3.5.2 ARM RV1109音视频对讲开发记录 说明 这是一份事后记录&#xff0c;主要记录的几个核心关键点&#xff0c;有可能很多细节没有记上&#xff0c;主要是方便后面自己再找回来! 版本 3.5.2 一些原因选的是这样一个旧的版本&#xff01; 新的开发最好选新一些的版…...

Unity用相机实现的镜子效果

首先登场 场景中的元素 mirror是镜子&#xff0c;挂着我们的脚本&#xff0c;Quad是一个面片。Camera是用来生成RenderTexture给面片的。里面的test1是我用来调试位置的球。 镜子size是大小&#xff0c;x是-2&#xff0c;为了反转一下贴图 相机直接可以禁用掉&#xff0c;用…...

计算机网络分类

按照覆盖范围分类 &#xff08;1&#xff09;个域网&#xff1a;通常覆盖范围在1&#xff5e;10m。 &#xff08;2&#xff09;局域网&#xff1a;通常覆盖范围在10m&#xff5e;1km。 &#xff08;3&#xff09;城域网&#xff1a;覆盖范围通常在5&#xff5e;50 km 。 &…...

AI AIgents时代 - (三.) AutoGPT和AgentGPT

前两篇讲解了Agent的原理和组件&#xff0c;这节我将给大家介绍两个agent项目&#xff0c;给出它们的工作原理和区别&#xff0c;并教大家亲手尝试使用 Agents&#x1f389; &#x1f7e2; AutoGPT&#x1f916;️ 我们的老朋友&#xff0c;之前文章也专门写过。AutoGPT 是一…...

Jmeter接口自动化和Python接口自动化,如何选择?

选择Jmeter或Python进行接口自动化测试取决于您的具体需求和环境。以下是一些可以考虑的因素&#xff1a; 1. 语言熟悉度&#xff1a;如果您对Java更熟悉&#xff0c;那么Jmeter可能是更好的选择。而如果您的团队或个人对Python更熟悉&#xff0c;那么Python可能是更好的选择。…...

Sqilte3初步教程

文章目录 安装创建数据库创建和删除表插入行数据 安装 Windows下安装&#xff0c;首先到下载页面&#xff0c;下载Windows安装软件&#xff0c;一般是 sqlite-dll-win32-*.zip sqlite-tools-win32-*.zip下载之后将其内容解压到同一个文件夹下&#xff0c;我把它们都放在了D:\…...

详解Python中的json库

目录 1. json简介2. dumps/loads3. dump/load4. jsonl格式 1. json简介 JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;用于在不同应用程序之间传递数据。它是一种文本格式&#xff0c;易于阅读和编写&#xff0c;同时也易于…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权

摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题&#xff1a;安全。文章将详细阐述认证&#xff08;Authentication) 与授权&#xff08;Authorization的核心概念&#xff0c;对比传统 Session-Cookie 与现代 JWT&#xff08;JS…...

xmind转换为markdown

文章目录 解锁思维导图新姿势&#xff1a;将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件&#xff08;ZIP处理&#xff09;2.解析JSON数据结构3&#xff1a;递归转换树形结构4&#xff1a;Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...

Monorepo架构: Nx Cloud 扩展能力与缓存加速

借助 Nx Cloud 实现项目协同与加速构建 1 &#xff09; 缓存工作原理分析 在了解了本地缓存和远程缓存之后&#xff0c;我们来探究缓存是如何工作的。以计算文件的哈希串为例&#xff0c;若后续运行任务时文件哈希串未变&#xff0c;系统会直接使用对应的输出和制品文件。 2 …...

数据库——redis

一、Redis 介绍 1. 概述 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、高性能的内存键值数据库系统&#xff0c;具有以下核心特点&#xff1a; 内存存储架构&#xff1a;数据主要存储在内存中&#xff0c;提供微秒级的读写响应 多数据结构支持&…...