Java变参、C/C++/Objective_C变参

/*
	java中变参方法,变参即参数列表不固定,但是参数类型是一样的,在使用时,形参变量是数组类型的引用
*/

public class AppEnter{

	public static void main(String[] args) throws Exception{

		AppEnter.unfixedArguments("one", "two", "three");
		AppEnter.unfixedArguments(100, "one", "two", "three");

	}

	//方法中只有一个变参
	public static void unfixedArguments(String...arguments){

		System.out.println("形参最后的类型是:" + arguments.getClass().getSimpleName());

		for (String argument : arguments) {

			System.out.println(argument);
		}
	}

	//方法中有固定参数时,变参必须位于最右边,即作为参数列表的最后
	public static void unfixedArguments(int fixedArgument, String...arguments){

		System.out.println("形参最后的类型是:" + arguments.getClass().getSimpleName());

		for (String argument : arguments) {

			System.out.println(argument);
		}
	}
}	

///////////////////////////////
C/C++/Objective_C语言中函数参数往往都是固定的,调用时只需要传递对应类型的实参即可;但是有些情况,需要向函数传递不固定的参数。
比如:printf(),使用时,最少一个参数,最多不限。

在头文件中是这样说明的它的:
int printf(const char *format, ...);
后面的三个点...表示printf参数个数是不定的. 

在介绍编写变参函数前,先了解下stdarg.h在几个相关的函数:

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

其中:
va_list是用于存放参数列表的数据结构。
va_start函数根据last参数的相关信息,来初始化参数列表。
va_arg函数用于从参数列表中取出一个参数,参数类型由type指定。
va_end函数执行清理参数列表的工作。 

系统给的帮助说明如下:
va_start()
       The  va_start() macro initializes ap for subsequent use by va_arg() and
       va_end(), and must be called first.
       The argument last is the name of the last argument before the  variable
       argument list, that is, the last argument of which the calling function
       knows the type.
       Because the address of this argument may  be  used  in  the  va_start()
       macro,  it should not be declared as a register variable, or as a func‐
       tion or an array type.
va_arg()
       The va_arg() macro expands to an expression that has the type and value
       of  the  next  argument in the call.  The argument ap is the va_list ap
       initialized by va_start().  Each call to va_arg() modifies ap  so  that
       the  next  call returns the next argument.  The argument type is a type
       name specified so that the type of a pointer to an object that has  the
       specified type can be obtained simply by adding a * to type.
       The  first use of the va_arg() macro after that of the va_start() macro
       returns the argument after last.   Successive  invocations  return  the
       values of the remaining arguments.
       If  there  is  no  next argument, or if type is not compatible with the
       type of the actual next argument (as promoted according to the  default
       argument promotions), random errors will occur.
       If  ap is passed to a function that uses va_arg(ap,type) then the value
       of ap is undefined after the return of that function.
va_end()
       Each invocation of va_start() must be matched by a corresponding  invo‐
       cation of va_end() in the same function.  After the call va_end(ap) the
       variable ap is undefined.  Multiple traversals of the list, each brack‐
       eted  by va_start() and va_end() are possible.  va_end() may be a macro
       or a function.

EXAMPLES
     The function foo takes a string of format characters and prints out the
     argument associated with each format character based on the type.

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

                   va_start(ap, fmt);
                   va_copy(ap2, ap);
                   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 */
                                   /* Note: char is promoted to int. */
                                   c = va_arg(ap, int);
                                   printf("char %c\n", c);
                                   break;
                           }
                   va_end(ap);
                   ...
                   /* use ap2 to iterate over the arguments again */
                   ...
                   va_end(ap2);
           }

说明:
va_start(ap, fmt);用于根据fmt初始化可变参数列表。
va_arg(ap, char *);用于从参数列表中取出一个参数,其中的char *用于指定所取的参数的类型为字符串。每次调用va_arg后,参数列表ap都会被更改,以使得下次调用时能得到下一个参数。
va_end(ap);用于对参数列表进行一些清理工作。调用完va_end后,ap便不再有效。
以上程序给了我们一个实现printf函数的是思路,即:通过调用va_start函数,来得到参数列表,然后我们一个个取出参数来进行输出即可。

例如:对于printf(“a=%d,b=%s,c=%c”,a,b,c)语句;fmt的值为a=%d,b=%s,c=%c,调用va_start函数将参数a,b,c存入了ap中。注意到:fmt中的%为特殊字符,紧跟%后的参数指明了参数类型. 

下面我们自定义一个打印函数,实现printf()的变参功能:
#include <stdarg.h>
void myprintf(char *fmt, ...)
{
    va_list ap;
    //基本类型:int double char char*
    int d;
    double f;
    char c;
    char *s;
    char flag;
    va_start(ap,fmt);
    while (*fmt){
        flag=*fmt++;
        if(flag!='%'){
            putchar(flag);
            continue;
        }
    flag=*fmt++;//记得后移一位
        switch (flag)
        {
            case 's':
                s=va_arg(ap,char*);
                printf("%s",s);
                break;
            case 'd': /* int */
                d = va_arg(ap, int);
                printf("%d", d);
                break;
            case 'f': /* double*/
                f = va_arg(ap,double);
                printf("%f", f);
                break;
            case 'c': /* char*/
                c = (char)va_arg(ap,int);
                printf("%c", c);
                break;
            default:
                putchar(flag);
                break;
        }
    }
    va_end(ap);
}

int main(int argc, const char * argv[]) {
    // insert code here...
    myprintf("One is %d, Two is %s", 99, "ABC");

    return 0;
}

myprintf变参数函数的编写,必须要传入一个参数fmt,用来告诉我们的函数怎样去确定参数的个数。我们的可变参数函数是通过自己解析这个参数来确定函数参数个数及类型的。

下面我们编写一个求和函数,其函数实现如下:
int sum(int cnt,...)
{
    int sum=0;
	int i;
    va_list ap;
    va_start(ap,cnt);
	for(i=0;i<cnt;++i){

		sum+=va_arg(ap,int);
	}

    va_end(ap);

	return sum;
} 

sum变参函数的编写,必须要传入一个参数cnt,用来告诉我们的函数体有多少个参数传入,这样for循环就知道循环多少次了。其实仔细思考下,如果参数cnt
不表示变参个数的话,那如何知道变参个数呢?办法就是,利用一个特殊值作为变参的最后一个传入,这个特殊值就意味着的变参的结束。

int sumOther(int first,...)
{
    int sum = first;

    va_list ap;
    va_start(ap,first);

    int temp = 0;
    while ((temp = va_arg(ap,int)) != 0) {

        sum += temp;
    }

    va_end(ap);

    return sum;
}

总结一下就是:通过va_start初始化参数列表(也就能得到具体的参数个数了,当然是间接的知道),然后使用va_arg函数从参数列表中取出你想要的参数,最后调用va_end执行清理工作。
时间: 2024-10-07 03:56:54

Java变参、C/C++/Objective_C变参的相关文章

python核心编程--笔记

python核心编程--笔记 的解释器options: 1.1 –d   提供调试输出 1.2 –O   生成优化的字节码(生成.pyo文件) 1.3 –S   不导入site模块以在启动时查找python路径 1.4 –v   冗余输出(导入语句详细追踪) 1.5 –m mod 将一个模块以脚本形式运行 1.6 –Q opt 除法选项(参阅文档) 1.7 –c cmd 运行以命令行字符串心事提交的python脚本 1.8 file   以给定的文件运行python脚本 2 _在解释器中表示最后

Go学习指南

学习Golang书籍&资料: 1. The Go Programming Language Specification:  http://golang.org/ref/spec 2. How to Write Go Code: http://golang.org/doc/code.html 3. Effective Go: http://golang.org/doc/effective_go.html 4. Go语言编程.pdf 5. Go语言程序设计.pdf 6. 学习GO语言.pdf 7.

14. 串口控制台建立

14. 串口控制台建立 串口控制台建立这一节的主要有三个内容: 1.控制台框架搭建 1.1控制台的分类介绍: 1.1.1菜单型控制台:就是选中设置好的数字或者字母选项后执行相应功能的控制台: 例如刚进入uboot之后的界面,就是菜单型控制台: 等待我们输入命令,来执行相应的操作.例如上面,如果此时我们输入1,就是进行Format the nand Flash的操作: 1.1.2解析型控制台:在上面的菜单型控制台里,选择5:Exit to command line:后会出现: 就进入了解析型控制台

go语言:函数参数传递详解

参数传递是指在程序的传递过程中,实际参数就会将参数值传递给相应的形式参数,然后在函数中实现对数据处理和返回的过程.比较常见的参数传递有:值传递,按地址传递参数或者按数组传递参数. 1.常规传递 使用普通变量作为函数参数的时候,在传递参数时只是对变量值得拷贝,即将实参的值复制给变参,当函数对变参进行处理时,并不会影响原来实参的值. 例如: package main import ( "fmt" ) func swap(a int, b int) { var temp int temp =

Swift与OC的语法简单对比

01-常量与变量   学习swift第一步打印Hello World print("Hello World") swift是不用加分号的 什么是常量? 常量是在程序运行过程中不能改变值的量 什么时变量? 变量是可以在程序运行过程中不断变化的量 在swift当中常量和变量必须在使用前声明 用let来声明常量,用var来声明变量 常量定义方式: 可以用任何你喜欢的字符作为常量和变量名,包括Unicode字符 常量与变量名不能包含以下: 数学符号,箭头,保留的(或者非法的)Unicode码位

java变参

java变参是通过数组来实现的 Object[] addAll(Object[] array1, Object... array2)和Object[] addAll(Object[] array1, Object[] array2)签名应该一致的. public class ArrayUtils { // Clone // ----------------------------------------------------------------------- /** * <p> * Sh

数据结构复习之n维数组实现(可变参数表的使用)

首先先介绍一下可变参数表需要用到的宏: 头文件:#include<cstdarg> void va_start( va_list arg_ptr, prev_param ); type va_arg( va_list arg_ptr, type ); void va_end( va_list arg_ptr ); va_list:用来保存宏va_start.va_arg和va_end所需信息的一种类型.为了访问变长参数列表中的参数,必须声明             va_list类型的一个对象

[C++模板]Clang3.9使用变参模拟实现CheckerFn和Checker

Clang3.9使用变参模拟实现CheckerFn和Checker 一,使用变参实现CheckerFn 1,头文件 /*********************************                                         * * Author : szyu * * Date : 2017.1.4 * ***********************************/ #ifndef __SZYU_CLANG__ #define __SZYU_CL

C语言可变参简介

C语言可变参简介 我们在C语言编程中会遇到一些参数个数可变的函数,例如printf()这个函数,它的定义是这样的:     int printf( const char* format, ...); 它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的,例如我们可以有以下不同的调用方法:     printf("%d",i);      printf("%s",s);     printf("the number is %d ,strin