STDARG(3)翻译

名字

stdarg, va_start, va_arg, va_end, va_copy可变参数列表。

概要

#include <stdarg.h>

void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);

描述

一个函数可能有不同数量的不同类型的参数。头文件<stdarg.h>声明了一个va_list类型,并且定义3个宏来处理被调函数的参数列表。被调函数必须声明一个被va_start, va_arg和va_end使用的类型为va_list的对象。

va_start()

va_start()宏初始化一个被后面va_arg()和va_end()使用的ap,并且必须率先调用。last是在可变参数列表之前的最后一个我们知道类型的参数的名字。因为va_start()宏可能会用到last的地址,所以不要把last声明成寄存器变量或者函数、数组类型。

va_arg()

va_arg()这个宏扩展到调用中的下一个参数的值和类型。ap就是由va_start()初始化的va_list类型的ap。每次调用va_arg(),它都会修改ap,使它的下一次调用返回下一个参数。参数type就是一个类型名,这样就可以获取一个类型对象了。

在调用va_start()之后第一次调用va_arg()它就返回last后面的第一个参数。后面的调用,依次返回剩下的参数的值。

如果后面没有其它参数了,或者type和实际的下一个参数不匹配(会按照默认参数扩展?),就会产生随机的错误。

如果ap在调用va_arg(ap, type)的时候是指向一个函数的,那么在这个函数返回的时候ap的值是未定义的。

va_end()

每次在一个函数里面调用va_start(),必须有一个va_end()与它进行匹配。用多对va_start()和va_end()多次遍历一个va_list也是可以的。va_end()可以是一个宏或者一个函数。

va_copy()

va_copy()将之前初始化的可变参数列表从src拷贝到dest。这个行为等价于先对dest做va_start(),然后调用获得src相同次数的va_arg()。

一个显而易见的实现是让va_list指向可变函数的栈帧。这样的话(目前最常见),这样的话,赋值操作好像也没什么问题。

va_list aq = ap;

不幸的是,有些系统也把va_list实现成一个指针数组。那这样的话就需要:

va_list aq;
*aq = *ap;

最后,对于参数传递到寄存器的系统,就有必要用va_start()分配内存,存储参数,并且表明哪个参数是下一个。这样的话va_arg()才可以对参数进行遍历。然后va_end()可以释放内存。为了解决这个问题,C99添加了一个宏va_copy()。那么上面的赋值就可以用下面的函数代替:

va_list aq;
va_copy(aq, ap);
...
va_end(aq);

每次调用va_copy(),必须在同一个函数里面调用对应的va_end()。有些系统不提供va_copy(),但是有__va_copy,这个是草案里面使用的名字。

属性

这部分使用的术语的解释可以参看attribute(7)。

接口属性
va_start(), va_end(), va_copy()线程安全性MT-safe
va_arg()线程安全性MT-safe race:ap

规范

va_start(), va_arg(), va_end()宏遵守C89,va_copy()遵守C99。

注释

这些宏和它们代替的历史上的宏并不兼容。一个后向兼容的版本可以在头文件<varargs.h>中找到。

历史的背景是:

#include <varargs.h>

void
foo(va_alist)
    va_dcl
{
    va_list ap;

    va_start(ap);
    while (...) {
        ...
        x = va_arg(ap, type);
        ...
    }
    va_end(ap);
}

有些系统,va_end包含一个“}”,va_start包含一个“{”,这样的话两个宏就必须出现在同一个函数里面,否则编译就不会通过。

BUGS

不像varargs宏,stdarg宏不允许程序员编码一个没有固定参数的函数。这个问题主要是在将varargs代码转换为stdarg代码的时候引入了很多工作量。当然,这个也给从可变参数函数内部将它所有的参数传递给一个有一个va_list参数的函数(比如vfprintf(3))带来了很多的困难。

例子

函数foo把一个格式字符串作为参数,并且根据每个格式字符表明的类型打印出每个参数。

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

void
foo(char *fmt, ...)
{
    va_list ap;
    int d;
    char c, *s;

    va_start(ap, fmt);
    while(*fmt)
        switch(*fmt++) {
        case 's':              /* string */
            s = va_arg(ap, char *);
            printf("string %s\n", s);
            break;
        case 'd':              /* int */
            d = va_arg(ap, int);
            printf("int %d\n", d);
            break;
        case 'c':              /* char */
            /* Need a cast hear since va_arg only
               takes fully promoted types */
            c = (char) va_arg(ap, int);
            printf("char %c\n", c);
            break;
        }
    va_end(ap);
}

版权

本页是Linux man-page项目4.15版的一部分。关于项目的描述,报bug相关信息,以及本页的最新版本可以在https://www.kernel.org/doc/man-pages/找到。

内容概要:本文详细介绍了基于FPGA的144输出通道可切换电压源系统的设计与实现,涵盖系统总体架构、FPGA硬件设计、上位机软件设计以及系统集成方案。系统由上位机控制软件(PC端)、FPGA控制核心和高压输出模块(144通道)三部分组成。FPGA硬件设计部分详细描述了Verilog代码实现,包括PWM生成模块、UART通信模块和温度监控模块。硬件设计说明中提及了FPGA选型、PWM生成方式、通信接口、高压输出模块和保护电路的设计要点。上位机软件采用Python编写,实现了设备连接、命令发送、序列控制等功能,并提供了一个图形用户界面(GUI)用于方便的操作和配置。 适合人群:具备一定硬件设计和编程基础的电子工程师、FPGA开发者及科研人员。 使用场景及目标:①适用于需要精确控制多通道电压输出的实验环境或工业应用场景;②帮助用户理解和掌握FPGA在复杂控制系统中的应用,包括PWM控制、UART通信及多通道信号处理;③为研究人员提供一个可扩展的平台,用于测试和验证不同的电压源控制算法和策略。 阅读建议:由于涉及硬件和软件两方面的内容,建议读者先熟悉FPGA基础知识和Verilog语言,同时具备一定的Python编程经验。在阅读过程中,应结合硬件电路图和代码注释,逐步理解系统的各个组成部分及其相互关系。此外,实际动手搭建和调试该系统将有助于加深对整个设计的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值