编程参考 - C语言可变参数

Variadic functions - cppreference.com

Variadic functions

Variadic functions are functions (e.g. printf) which take a variable number of arguments.

The declaration of a variadic function uses an ellipsis as the last parameter, e.g.

int printf(const char* format, ...);. See variadic arguments for additional detail on the syntax and automatic argument conversions.

Accessing the variadic arguments from the function body uses the following library facilities:

Types

va_list: holds the information needed by va_start, va_arg, va_end, and va_copy (typedef)

Macros

Defined in header <stdarg.h>

va_start:

enables access to variadic function arguments

(function macro)

va_arg:

accesses the next variadic function argument

(function macro)

va_copy:

(C99)

makes a copy of the variadic function arguments

(function macro)

va_end:

ends traversal of the variadic function arguments

(function macro)

Example

Run online compiler: Coliru

Print values of different types.

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| #include <stdarg.h> #include <stdio.h> void simple_printf(const char* fmt, ...) { va_list args; for (va_start(args, fmt); *fmt != '\0'; ++fmt) { switch(*fmt) { case 'd': { int i = va_arg(args, int); printf("%d\n", i); break; } case 'c': { // A 'char' variable will be promoted to 'int' // A character literal in C is already 'int' by itself int c = va_arg(args, int); printf("%c\n", c); break; } case 'f': { double d = va_arg(args, double); printf("%f\n", d); break; } default: puts("Unknown formatter!"); goto END; } } END: va_end(args); } int main(void) { simple_printf("dcff", 3, 'a', 1.969, 42.5); } |

Output:

3

a

1.969000

42.50000


Variadic arguments - cppreference.com

Variadic functions are functions that may be called with different number of arguments.

Only prototyped function declarations may be variadic. This is indicated by the parameter of the form ... which must appear last in the parameter list and must follow at least one named parameter(until C23). The ellipsis parameter and the proceeding parameter must be delimited by ,.

// Prototyped declaration

int printx(const char* fmt, ...); // function declared this way

printx("hello world"); // may be called with one

printx("a=%d b=%d", a, b); // or more arguments

int printz(...); // OK since C23 and in C++

// Error until C23: ... must follow at least one named parameter

// int printy(..., const char* fmt); // Error: ... must be the last

// int printa(const char* fmt...); // Error in C: ',' is required; OK in C++

At the function call, each argument that is a part of the variable argument list undergoes special implicit conversions known as default argument promotions.

Within the body of a function that uses variadic arguments, the values of these arguments may be accessed using the <stdarg.h> library facilities.

Notes

Although old-style (prototype-less) function declarations allow the subsequent function calls to use any number of arguments, they are not allowed to be variadic (as of C89). The definition of such function must specify a fixed number of parameters and cannot use the stdarg.h macros.

// old-style declaration, removed in C23

int printx(); // function declared this way

printx("hello world"); // may be called with one

printx("a=%d b=%d", a, b); // or more arguments

// the behavior of at least one of these calls is undefined, depending on

// the number of parameters the function is defined to take

Example

#include <stdio.h>

#include <time.h>

#include <stdarg.h>

void tlog(const char* fmt,...)

{

char msg[50];

strftime(msg, sizeof msg, "%T", localtime(&(time_t){time(NULL)}));

printf("[%s] ", msg);

va_list args;

va_start(args, fmt);

vprintf(fmt, args);

va_end(args);

}

int main(void)

{

tlog("logging %d %d %d...\n", 1, 2, 3);

}

Output:

10:21:38\] logging 1 2 3... *** ** * ** *** [vprintf, vfprintf, vsprintf, vsnprintf, vprintf_s, vfprintf_s, vsprintf_s, vsnprintf_s - cppreference.com](https://en.cppreference.com/w/c/io/vfprintf "vprintf, vfprintf, vsprintf, vsnprintf, vprintf_s, vfprintf_s, vsprintf_s, vsnprintf_s - cppreference.com") Defined in header \ (1) int vprintf( const char\* format, va_list vlist ); (until C99) int vprintf( const char\* restrict format, va_list vlist ); (since C99) (2) int vfprintf( FILE\* stream, const char\* format, va_list vlist ); (until C99) int vfprintf( FILE\* restrict stream, const char\* restrict format, va_list vlist ); (since C99) (3) int vsprintf( char\* buffer, const char\* format, va_list vlist ); (until C99) int vsprintf( char\* restrict buffer, const char\* restrict format, va_list vlist ); (since C99) (4) (since C99) int vsnprintf( char\* restrict buffer, size_t bufsz, const char\* restrict format, va_list vlist ); (5) (since C11) int vprintf_s( const char\* restrict format, va_list vlist ); (6) (since C11) int vfprintf_s( FILE\* restrict stream, const char\* restrict format, va_list vlist ); (7) (since C11) int vsprintf_s( char\* restrict buffer, rsize_t bufsz, const char\* restrict format, va_list vlist ); (8) (since C11) int vsnprintf_s( char\* restrict buffer, rsize_t bufsz, const char\* restrict format, va_list vlist ); Loads the data from the locations, defined by vlist, converts them to character string equivalents and writes the results to a variety of sinks. 1) Writes the results to stdout. 2) Writes the results to a file stream stream. 3) Writes the results to a character string buffer. 4) Writes the results to a character string buffer. At most bufsz - 1 characters are written. The resulting character string will be terminated with a null character, unless bufsz is zero. If bufsz is zero, nothing is written and buffer may be a null pointer, however the return value (number of bytes that would be written not including the null terminator) is still calculated and returned. **Parameters** stream - output file stream to write to buffer - pointer to a character string to write to bufsz - up to bufsz - 1 characters may be written, plus the null terminator format - pointer to a null-terminated character string specifying how to interpret the data vlist - variable argument list containing the data to print. The format string consists of ordinary byte characters (except %), which are copied unchanged into the output stream, and conversion specifications. **Return value** 1-3) The number of characters written if successful or negative value if an error occurred. 4) The number of characters written if successful or negative value if an error occurred. If the resulting string gets truncated due to buf_size limit, function returns the total number of chara **Example** #include \ #include \ #include \ void debug_log(const char\* fmt, ...) { struct timespec ts; timespec_get(\&ts, TIME_UTC); char time_buf\[100\]; size_t rc = strftime(time_buf, sizeof time_buf, "%D %T", gmtime(\&ts.tv_sec)); snprintf(time_buf + rc, sizeof time_buf - rc, ".%06ld UTC", ts.tv_nsec / 1000); va_list args1; va_start(args1, fmt); va_list args2; va_copy(args2, args1); char buf\[1+vsnprintf(NULL, 0, fmt, args1)\]; va_end(args1); vsnprintf(buf, sizeof buf, fmt, args2); va_end(args2); printf("%s \[debug\]: %s\\n", time_buf, buf); } int main(void) { debug_log("Logging, %d, %d, %d", 1, 2, 3); } **Possible output:** 02/20/15 21:58:09.072683 UTC \[debug\]: Logging, 1, 2, 3

相关推荐
Gain_chance1 小时前
36-学习笔记尚硅谷数仓搭建-DWS层数据装载脚本
大数据·数据仓库·笔记·学习
肖永威1 小时前
macOS环境安装/卸载python实践笔记
笔记·python·macos
暗光之痕2 小时前
Unreal5研究笔记 Actor的生命周期函数
笔记·unreal engine
Gain_chance2 小时前
35-学习笔记尚硅谷数仓搭建-DWS层最近n日汇总表及历史至今汇总表建表语句
数据库·数据仓库·hive·笔记·学习
宵时待雨2 小时前
STM32笔记归纳9:定时器
笔记·stm32·单片机·嵌入式硬件
m0_719084113 小时前
React笔记张天禹
前端·笔记·react.js
r i c k5 小时前
数据库系统学习笔记
数据库·笔记·学习
shandianchengzi6 小时前
【小白向】错位排列|图文解释公考常见题目错位排列的递推式Dn=(n-1)(Dn-2+Dn-1)推导方式
笔记·算法·公考·递推·排列·考公
浅念-6 小时前
C语言编译与链接全流程:从源码到可执行程序的幕后之旅
c语言·开发语言·数据结构·经验分享·笔记·学习·算法
The森7 小时前
Linux IO 模型纵深解析 01:从 Unix 传统到 Linux 内核的 IO 第一性原理
linux·服务器·c语言·经验分享·笔记·unix