`
lobin
  • 浏览: 425929 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

C:不定长参数

 
阅读更多

C语言在定义函数的时候,有多少个参数,每个参数的参数名,参数类型都是需要明确指定的。但C语言还支持不定长参数,可以不用确定到底有多少个参数,这些参数的参数名以及类型的。在调用的时候,如果是不定长参数,是可以传任意多个参数。这使得在传递参数时变得更灵活更强大。

 

C语言中函数定义形式

void fn(int arg) 

{

 

}

如果有多个参数,用逗号(,)分隔。

 

C语言中不定长参数的定义形式

void fn(int arg0, ...)

{

 

}

C语言定义不定长参数时,前面必须要有个参数,这个参数必须要明确参数名和参数类型,也就是说不定长参数必须是函数的第二个参数。

 

调用

调用时可以传递任意多个参数。如上面的例子,在调用时:

fn(5, 0, 1, 2, 3, 4);

当然还可以传递更多个参数。

 

不定长参数接收问题

在接收不定长参数的时候,因为没有指定到底有多少个参数,也不知道到底传了多少个参数以及这些参数的参数名称和类型,所以按照正常情况是无法接收这些参数的。

 

C标准库提供了几个和不定长参数相关的宏。

 

不定长参数相关的操作

 

C标准库提供了几个和不定长参数相关的宏。

va_list

 

void va_start (va_list ap, paramN);

 

type va_arg (va_list ap, type)

 

void va_end (va_list ap);

通过这几个宏可以很方便的接收不定长参数。

 

另一个和不定长参数相关的函数:

int vsprintf (char * s, const char * format, va_list arg );

 

不定长参数个数和类型问题

虽然上面提供的几个宏可以很方便的接收不定长参数。但我们还是不知道到底有多少个参数,也不知道到底传了多少个参数以及这些参数的参数类型。上面的几个宏也不能确定到底有多少个参数,也不知道到底传了多少个参数以及这些参数的参数类型。

 

va_start很容易理解,就是开始接收,它会初始化ap,以便于接收paramN后面的不定长参数,这个paramN就是我们上面说的不定长参数前面的那个参数。

 

va_arg开始遍历去取每一个参数,但这里我们需要指定要取的参数的类型,这恰恰是我们不知道的。

 

va_end结束接收不定长参数,但我们恰恰不知道到底有多少个参数,也不知道到底传了多少个参数。

 

不定长参数的实际应用

基于上面提到的问题,在实际应用的时候比较困难。通常,我们在使用不定长参数的时候,我们会约定好不定长参数的类型和传递的参数个数,对于传递的参数个数,可以使用第1个参数来指定实际有多少个参数。

 

当然,这有时候使得不定长在实际使用的时候变得不太灵活,甚至还可能会出现问题。

 

虽然有事先约定好,但其实还是可以任意多个参数,任意的类型。假设规定参数的个数为5个,类型为int型,如果实际传了6个,还传了其他类型的参数的话就出问题了。

 

不定长参数灵活用法

可以参考C标准库函数printf来实现更灵活的使用不定长参数。

 

下面有参考printf函数灵活使用不定长参数的例子。

 

C标准库函数中不定长参数的用法

C标准库函数中的很多io输入输出函数都用到了不定长参数。最常见的就是我们常用到的printf函数。

 

int printf ( const char * format, ... );

 

int scanf ( const char * format, ... );

 

int sprintf ( char * str, const char * format, ... );

 

int sscanf ( const char * s, const char * format, ...);

 

int fprintf ( FILE * stream, const char * format, ... );

 

int fscanf ( FILE * stream, const char * format, ... );

 

int snprintf ( char * s, size_t n, const char * format, ... );

 

等等。

 

不定长参数

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

void test(char *fmt, ...)
{
  char *p;
  va_list vl;
  char c;

  va_start(vl, fmt);

  for (p = fmt; *p; p++)
  {
	if (*p == '%')
	{
      c = va_arg(vl, char);
	  printf("param %c\n", c);
	  _asm mov ah, 0eh;
	  _asm mov al, c;
      _asm mov bx, 0fh;
      _asm int 10h;
	  printf("\n");
	}
    
  }
  va_end(vl);
}

int main()
{
  test("%%%%%%%\n", 'a', 'b', 'c', 'd', 'e', 'f', 'g');
  return 0;
}

 

va_arg获取参数

不定长参数中传递的参数是什么类型,在接收指定参数时也采用什么类型。比如,如果是int类型参数,那么在使用va_arg获取的时候也指定int获取该参数:

int arg = va_arg(vl, int);

 

但也有例外,如果是char类型的参数,在接收的时候是不能通过char来获取该参数的。如下面的例子:

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

void test(char *fmt, ...)
{
  char *p;
  va_list vl;
  char c;

  va_start(vl, fmt);

  for (p = fmt; *p; p++)
  {
	if (*p == '%')
	{
      c = va_arg(vl, char);
	  printf("param %c\n", c);
	  printf("\n");
	}
    
  }
  va_end(vl);
}

int main()
{
  test("%%%%%%%\n", 'a', 'b', 'c', 'd', 'e', 'f', 'g');
  return 0;
}

我们在编译上面的程序的时候,会有个警告:

>gcc va_list3.c -o va_list3

va_list3.c: In function ‘test’:

va_list3.c:27:11: warning: ‘char’ is promoted to ‘int’ when passed through ‘...’

va_list3.c:27:11: note: (so you should pass ‘int’ not ‘char’ to ‘va_arg’)

va_list3.c:27:11: note: if this code is reached, the program will abort

 

并且在运行的时候报错:

>.\va_list3

      3 [main] va_list3 4052 open_stackdumpfile: Dumping stack trace t

o va_list3.exe.stackdump

 

 

这涉及到C标准中的一个“提升规则”

写道
In function calls not in the scope of a function prototype, integer arguments have the integer promotions applied and float arguments are widened to double. It is not possible in such a call to pass an unconverted char or float argument. Function prototypes give the programmer explicit control over the function argument type conversions, so that the often inappropriate and sometimes inefficient default widening rules for arguments can be suppressed by the implementation.

 

在这个例子中,传入的字符类型char将被提升为int类型。包括short类型也是。float类型将被提升为double类型。

 

这个例子跟上面的例子差不多呀, 上面的例子通过char来获取参数可以成功,这个怎么就报错?在上面的那个例子中我是使用tc编译的,而这个程序我是使用gcc编译的。在tc下是可以这样获取参数,在gcc下是不可以的。这也跟编译器有关。

 

 

0
0
分享到:
评论

相关推荐

    C语言中不固定多个参数的实现

    C语言中不定参数的实现

    python不定长参数详解

    Python 自定义函数中存在两种不定长参数: - 第一种是 `*XXX`,它允许你传递任意数量的位置参数,这些参数会被打包成一个元组(tuple)。在调用函数时,你可以不必明确指定参数名,直接传入参数值。 - 第二种是 `**...

    c可变参数用法 命令

    在C语言中,可变参数函数是指那些能够接受不定数量参数的函数。这种特性在很多场合下都非常有用,尤其是在日志记录、错误处理以及网络通信等场景中。本文将通过一个具体的示例来深入探讨C语言中可变参数的具体用法...

    STM32串口接收不定长数据程序

    STM32串口接收不定长数据程序是嵌入式开发中的常见需求,尤其在通信协议设计和调试过程中。STM32作为一款广泛应用的ARM Cortex-M系列微控制器,其丰富的外设接口,包括串行通信接口(UART),为实现这一功能提供了...

    STM32F407 DMA+串口接收不定长数据程序

    在提供的压缩包文件"DMA+串口接收不定长数据"中,应该包含实现这一功能的C代码文件,如`main.c`、`stm32f4xx_hal_msp.c`、`stm32f4xx_it.c`等,以及相应的头文件。这些文件包含了初始化串口、DMA、中断服务程序以及...

    STC单片机串口中断接收不定长数据

    在STC单片机中,串口通信是常见的一种数据传输方式,尤其在与上位机或者其他的嵌入式设备交互时,中断接收不定长数据的机制显得尤为重要。下面将详细讲解STC单片机串口通信中断接收不定长数据的基本原理、实现方法...

    C技巧:结构体参数转成不定参数

    这种情况下,C语言提供了变长参数列表的功能,通常通过`stdarg.h`头文件中的类型和函数来实现。本文将探讨如何将一个接受结构体参数的函数转换为接受可变参数的函数。 首先,了解`stdarg.h`头文件中的关键类型和...

    不定参数在C语言中的应用实例

    不定参数在C语言中的应用实例:不定参数当年做为C/C++语言一个特长被很多人推崇,但是实际上这种技术并没有应用很多。除了格式化输出之外,我实在没看到多少应用。主要原因是这种技术比较麻烦,副作用也比较多,而...

    C语言可变参数列表:深入解析与应用实践

    在C语言中,可变参数列表提供了一种灵活调用函数的方式,允许函数接受不定数量的参数。这种特性在编写需要接受不同数量参数的通用函数时非常有用,例如打印函数。本文将深入解析C语言中可变参数列表的使用方法,包括...

    不定参数函数1.pdf

    在编程中,不定参数函数是一种特殊的函数,其...这种方法在C语言标准库中广泛应用,例如在printf或scanf函数中就可以看到不定参数的应用。通过正确地使用这些宏,我们可以在自己的函数中灵活地处理不确定数量的参数。

    用C语言实现参数个数可变的函数

    1. 可变参数列表的实现原理:通过C语言预定义的宏va_start、va_arg、va_end在stdarg.h头文件中,可以使得函数访问参数个数不定的参数列表。 2. va_start宏的作用:va_start宏初始化参数列表,为后续使用va_arg宏...

    不定参数函数2.pdf

    不定参数函数是C/C++语言中一类特殊的函数,它们允许函数接收不确定数量的参数。在C/C++标准库中,这种类型的函数并不多见,但以printf()和scanf()系列函数为代表的输入输出函数以及exec*()系列函数执行外部程序时...

    STM32_FreeRTOS_USART串口通信接收不定长数据

    STM32基于Cubemx和FreeRTOS的USART串口通信是嵌入式开发中的重要环节,特别是对于处理不定长数据的接收,这涉及到实时操作系统(RTOS)的任务调度和中断处理。以下是对这个主题的详细解释: 首先,STM32是意法...

    不定参数函数

    不定参数函数是编程语言中的一种特性,允许我们定义可以接受任意数量参数的函数。这种功能在处理各种场景时非常有用,比如需要一个函数能够灵活地处理任意数量的输入数据,或者在不知道具体参数数量的情况下创建通用...

    第八天 10函数参数详解【千锋Python人工智能学院】1

    有两种类型的不定长参数: - `*args`:用于接收未命名的位置参数,它将这些参数作为元组存储。 - `**kwargs`:用于接收关键字参数,它将这些参数作为字典存储。 例如: ```python def test(a, b, *args, **kwargs...

    详解-C语言可变参数-va-list和-vsnprintf及printf实现.pdf

    C语言中的可变参数是一种特殊的函数参数形式,它允许函数接受不定数量和类型的参数。在日常开发中,我们常用的 printf 函数就是使用了可变参数的接口。今天,我们将深入探索 C 语言可变参数的实现机制。 首先,让...

    stm32f070 HALL库 dma+Uart+不定长接收数据

    在本项目中,我们关注的是如何利用STM32F070进行HALL传感器(如LTC2942)的数据采集,并通过DMA(直接存储器访问)和UART(通用异步收发传输器)实现串口的不定长数据接收。 首先,我们需要了解STM32CubeMX,这是一...

    C#七参数转换代码

    在上述示例中,`SevenParameterConversion`方法接收七个不同类型的参数:一个整数、一个字符串、一个双精度浮点数、一个布尔值、一个日期时间、一个对象和一个整数列表。在方法体内部,你可以根据需求对这些参数进行...

Global site tag (gtag.js) - Google Analytics