迅当网络深圳外贸网站建设,大型网站建设优化排名,平面设计平台有哪些,个人网页制作模板田田田田田田田田文章目录 C语言的不定参C的不定参 C语言的不定参
C语言的不定参数最常见的应用示例就是printf函数#xff0c;如下#xff0c;参数列表中的...表示不定参数列表
#include stdio.h
int printf(const char *format, ...);试着模拟实现C语言的printf函数
void myprin… 文章目录 C语言的不定参C的不定参 C语言的不定参
C语言的不定参数最常见的应用示例就是printf函数如下参数列表中的...表示不定参数列表
#include stdio.h
int printf(const char *format, ...);试着模拟实现C语言的printf函数
void myprintf(const char *fmt, ...)
{//TODO
}C语言中对于...不定参列表要用va_*系列宏函数操作
#include stdarg.hvoid 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);va_list va_list可以理解为一个指针类型开始时通过调用va_start它会指向不定参列表的第一个参数 va_start 我们知道C/C的函数参数通过压栈的方式传入不定参列表的多个参数也需要压栈。 va_start的作用是使ap指向不定参列表的第一个参数。通过不定参数列表前的最后一个函数参数找到不定参列表的首元素并使apva_list类型的指针指向首元素。因此C函数使用...不定参数前面至少包含一个其它参数由它提供不定参数的起始位置。 va_arg va_arg的作用是在不定参数列表中从ap指向的参数开始逐个返回type类型的数据一般需要循环调用va_arg在此过程中ap会不断往后走 va_end ap使用结束后就失效了为了避免野指针的引用va_end可以销毁ap指针 va_copy 拷贝src到dest使得二者指向同一个不定参数列表src不用再次调用va_start但要调用va_end
Test Demo
void myprintf(size_t num, ...)
{va_list ap1;va_start(ap1, num);va_list ap2;va_copy(ap2, ap1);for (int i 0; i num; i){char ch va_arg(ap1, int);std::cout ch;}std::cout std::endl;for (int i 0; i num; i){char ch va_arg(ap2, int);std::cout ch;}std::cout std::endl;va_end(ap1);va_end(ap2);
}int main()
{myprintf(3, L, O, L);return 0;
}⭕输出结果
[ckfVM-8-12-centos 1.before]$ ./vargs
LOL
LOL注意va_arg对于可变参数的处理是有一些规则的特别是对于小整数类型如char和float。这些类型在传递给va_arg时会被默认转换为int和double而不是它们的实际类型。因此在Test Demo中对于传入的char类型参数在调用va_arg时也应该指定type为int获得返回值后再转换为实际类型char。
以下函数可以对不定参数列表进行格式化操作。
#include stdarg.hint vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);它们的作用与printf相同都可以通过参数format对不定参数进行格式化。区别在于printf使用不定参...作为格式化的数据而上面以v开头printf结尾的函数使用ap指向的不定参数列表作为格式化的数据。除此之外内部的区别就在于输出的方向了vprintf将格式化后的字符串输出到stdoutvfprintf输出到指定的文件流vsprintf和vsprintf输出到指定的内存空间str且后者可以指定输出的字节个数。
Test Demo
void myprintf(const char *fmt, ...)
{va_list ap;va_start(ap, fmt);char str[64] {0};int len vsnprintf(str, sizeof(str), fmt, ap);str[len] 0;std::cout str std::endl;va_end(ap);
}
int main()
{myprintf(%s %c %d, 你好, !, 2024);return 0;
}⭕输出结果
[ckfVM-8-12-centos 1.before]$ ./vargs
你好 ! 2024C的不定参
补充
args参数包作为参数传递给另一个函数时记得加...表示这个args参数是不定参数包函数接收Args...类型的参数包时通常可以将参数设置为万能引用减少拷贝的成本C11标准库中很多构造方法都使用了以不定参数包为参数的条目方便一些无法缺点参数个数的实例的构造
例如
std::make_shared由于并不确定构造智能指针指向的对象类型需要传入多少参数C11使用了Args不定参数包
emplace函数C11很多容器都重载了这个函数emplace支持可变参数包并且用参数包中的参数作为新插入元素构造函数的参数。
Test Demo
template class T
void myprintfcpp(T val) // 终止函数
{std::cout val;
}template class T, class... Args
void myprintfcpp(T val, Args ...args)
{std::cout val;myprintfcpp(std::forwardArgs(args)...);
}int main()
{myprintfcpp(3, L, O, L);std::cout std::endl;return 0;
}⭕输出结果
[ckfVM-8-12-centos 1.before]$ ./vargs
3LOLEND…