va_list(),va_start(),va_arg(),va_end() 详细解析

va_list(),va_start(),va_arg(),va_end() 详细解析

这四个函数在 C 语言中常用于对函数参数数量和类型不定的情况进行处理。下面将详细解析这四个函数。

va_list

它是 C 标准库中的一个类型,通常是一个指针,指向参数列表的起始位置。它用于存储从 va_start() 开始到参数列表最后一个参数数据地址的位置。

va_start

va_start() 宏用于将 va_list 指向参数列表的起始位置。

语法如下:

void va_start(va_list ap, last);

其中,ap 是指针,指向参数列表的开始位置,last 是函数中的最后一个命名参数。

以下是一个示例:

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

void printNumbers(int count, ...) {
  va_list ap;
  int i;

  va_start(ap, count); // 将ap指向第一个可变参数的地址

  for (i=0; i<count; i++) {
    int value = va_arg(ap, int); // 读取下一个int类型参数
    printf("%d ", value);
  }

  va_end(ap); // 结束时释放ap指向的内存
}

int main() {
  printNumbers(3, 1, 2, 3); // 输出 1 2 3 
  return 0;
}

在上述示例中,va_list 类型的变量 ap 是用于存储从 va_start() 开始到可变参数列表最后一个参数数据地址的位置。va_start() 的第一个参数就是 ap,第二个参数是函数中的最后一个固定参数,这里是 countva_start() 实现了 "ap = &count + sizeof(count)" 的功能,即通过传递 count 变量的地址来确定可变参数的起始地址。

va_arg

va_arg() 函数用于返回当前的可变参数,然后将 va_list 指向下一个参数。va_arg() 的原型如下:

type va_arg(va_list ap, type);

其中 ap 是使用 va_start() 初始化的 va_list 类型指针,type 是参数的类型。

以下是一个示例:

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

double average(int count, ...) {
  va_list ap;
  int i;
  double sum = 0;

  va_start(ap, count);

  for (i=0; i<count; i++) {
    sum += va_arg(ap, double);
  }

  va_end(ap);

  return sum/count;
}

int main() {
  printf("Average = %f\n", average(3, 1.0, 2.0, 3.0)); // 输出 Average = 2.000000
  return 0;
}

在上述示例中, va_arg() 函数每次调用都返回可变参数列表中的下一个参数,类型由第二个参数 type 决定,同时将指向 va_list 的指针向后移动类型所占用的字节数。

va_end

va_end() 宏用于结束可变参数的获取。它接受一个 va_list 类型的参数,并清除释放在调用 va_start() 时建立的内存。

语法如下:

void va_end(va_list ap);

以下是一个示例:

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

void foo(int count, ...) {
  va_list ap;
  int i;

  va_start(ap, count);

  for (i=0; i<count; i++) {
    int value = va_arg(ap, int);
    printf("%d ", value);
  }

  va_end(ap);
}

int main() {
  foo(3, 1, 2, 3); // 输出 1 2 3 
  return 0;
}

在上述示例中,va_end() 释放了 va_list 指针 ap,因此在 va_end()ap 必须重新初始化要重新使用它。

以上就是 va_list(),va_start(),va_arg(),va_end() 函数的详细解析。这些函数是处理参数列表不定的函数非常有用的工具。

示例

下面还演示一下如何使用 va_list()va_start()va_arg()va_end() 函数来实现可变参数的函数:

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

int sum(int num, ...) {
  va_list valist;
  int sum = 0, i;

  va_start(valist, num);

  for (i = 0; i < num; i++)
    sum += va_arg(valist, int);

  va_end(valist);

  return sum;
}

int main() {
  printf("Sum = %d\n", sum(3, 1, 2, 3)); // 输出 Sum = 6 
  printf("Sum = %d\n", sum(4, 2, 4, 6, 8)); // 输出 Sum = 20 
  return 0;
}

在上述示例中,函数 sum() 接受任意数量的参数,并返回它们的总和。它使用了 va_list()va_start()va_arg()va_end() 函数来处理不定数目的参数列表,其中 va_start() 用于初始化 va_list 中的变量,va_arg() 用于按顺序访问每个参数,va_end() 用于清理内存。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:va_list(),va_start(),va_arg(),va_end() 详细解析 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C++如何实现二叉树链表

    C++可以通过定义结构体来表示二叉树链表节点,结构体中包含左右子节点指针和数据域。通过指针来实现二叉树的构建和遍历。 以下是具体的实现步骤: 1. 定义结构体 首先我们需要定义一个结构体来表示二叉树链表节点,结构体定义如下: struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNod…

    C 2023年5月23日
    00
  • C++的指针,引用和STL详解

    C++的指针,引用和STL详解 指针 指针是C++语言中非常重要的一个概念,它是一个变量,其值为另一个变量的地址。指针的用途很广泛,它经常被用于动态的内存分配和数据结构中。 指针的定义和使用 指针的定义使用符号*,例如: int *p; 这个语句定义了一个名为p的指向int类型的指针。指针变量必须初始化才能使用,一般有两种方式: 直接初始化赋值,例如: in…

    C 2023年5月22日
    00
  • C++中的多态问题—理解虚函数表及多态实现原理

    以下是“C++中的多态问题—理解虚函数表及多态实现原理”的详细攻略: 什么是多态 多态是指在C++中,可以使用指向基类的指针或引用,来调用子类重载后的方法或重写的方法,达到动态调用的效果。多态可以提高代码的可读性和复用性,让代码变得更具扩展性和灵活性。 C++多态实现原理 C++中多态的实现原理主要是利用了虚函数和虚函数表的机制。虚函数是一种特殊的成员函数,…

    C 2023年5月22日
    00
  • 比特币真的值得长期持有和投资吗一文弄懂

    “比特币真的值得长期持有和投资吗” 完整攻略 1. 什么是比特币? 比特币是一种基于区块链技术的加密数字货币,由匿名的发明者“中本聪”在2009年发布。比特币的交易和管理是通过去中心化的方式进行,独立于中央机构或政府控制。 2. 比特币的特点 2.1 去中心化 比特币的交易和管理不需要中央机构或政府控制,而是由全球网络的节点共同维护、管理。 2.2 匿名性 …

    C 2023年5月22日
    00
  • C语言实现简单的抽奖系统

    下面是“C语言实现简单的抽奖系统”的完整攻略: 1. 设计思路 抽奖系统需要具备以下功能: 输入参加抽奖的人员名单。 随机抽取中奖者。 输出中奖者名单。 因此我们需要设计以下几个模块: 输入模块:获取所有参与抽奖的人名,并保存在数组中。 抽奖模块:使用随机数生成器,在参与抽奖的人员数组中随机选择一个中奖者。 输出模块:将中奖者的名字输出。 2. 代码实现 下…

    C 2023年5月23日
    00
  • C语言 array数组的用法详解

    C语言 array数组的用法详解 在C语言中,array数组是一种最基本的数据结构之一。它是一组相同类型的数据元素所组成的,这些数据元素可以按照一定的次序进行存储和访问。本文将详细讲解array数组的定义、初始化、使用等相关操作。 一、定义array数组 数组的定义格式如下: <数据类型> <数组名>[<数组长度>]; 其…

    C 2023年5月23日
    00
  • 关于C#版Nebula客户端编译的问题

    关于C#版Nebula客户端编译的问题,我将提供一份详细攻略,让您能对C#版Nebula客户端的编译过程有更深入的理解。 前置要求 在开始编译C#版Nebula客户端之前,我们需要先安装相关的开发工具和依赖库。 Visual Studio – 用于开发和编译C#项目的集成开发环境。 Git – 用于从Github上获取Nebula客户端的源代码。 .NET框…

    C 2023年5月23日
    00
  • C语言实现C++继承和多态的代码分享

    下面我就为你介绍一下如何用C语言实现C++继承和多态的代码分享。 1. 前言 在C语言中,虽然没有C++那样的继承和多态特性,但是我们可以通过结构体和函数指针的方式来实现类似的功能。下面将介绍如何使用C语言来实现类似C++中的继承和多态。 2. 实现继承 我们可以通过结构体来实现继承。具体步骤如下: 定义父类 typedef struct _animal {…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部