可变参数的格式化输出
Posted green-cnblogs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可变参数的格式化输出相关的知识,希望对你有一定的参考价值。
本文描述了将可变参数(variadic)按照格式化字符串的方式输出至标准输出(stdout)或文件流(ofstream)的一种实现方案,并加以了验证。
◆ 解法
通过可变参数函数(variadic function)和可变参数模板(variadic template),能够接受个数不定的参数。两种接受参数方式与两种输出目的地的组合,可以得到四种情况,
- 可变参数函数输出至标准输出(A)
- 可变参数模板输出至标准输出(B)
- 可变参数函数输出至文件流(C)
- 可变参数模板输出至文件流(D)
结合 *printf 系列输出函数以及变参标准库(<cstdarg>)中的宏定义和类型(va_*),可实现变参格式化输出的功能。
◆ 示例
以下代码片段(variadic_printf.cpp)展示了此实现方案,
可变参数函数输出至标准输出(A),
static void A(const char* fmt, ...)
std::va_list args; // #1
va_start(args, fmt);
std::vfprintf(stdout, fmt, args); // #2
// or
// std::vprintf(fmt, args);
va_end(args);
使用 std::va_list 对象与 va_start (#1)访问可变参数;然后由 std::vfprintf() 或 std::vprintf() 函数将可变参数输出(#2)至标准输出;最后用 va_end 宏结束对可变参数的访问。
可变参数模板输出至标准输出(B),
template <class... Types>
static void C(const char* fmt, const Types&... args)
std::fprintf(stdout, fmt, args...); // #3
// or
// std::printf(fmt, args...);
直接由 std::fprintf() 或 std::printf() 函数输出(#3)。
可变参数函数输出至文件流(C),
static void C(const char* fmt, ...)
std::va_list args, copied;
va_start(args, fmt);
va_copy(copied, args); // #4
char* buffer = new char[std::vsnprintf(nullptr, 0, fmt, copied) + 1]; // +1 for \'\\0\'
std::vsprintf(buffer, fmt, args); // #5
stream << buffer;
delete[] buffer;
va_end(copied);
va_end(args);
使用 std::va_list 对象与 va_start 访问可变参数;可变参数的一份拷贝用于 std::vsnprintf() 函数计算待输出字符串的长度,并依此长度开辟存放字符串的临时空间(#4);再由 std::vsprintf() 函数将可变参数输出至临时空间中(#5),紧接着输出至文件流;最后释放临时空间并结束对可变参数的访问。
可变参数模板输出至文件流(D),
template <class... Types>
static void D(const char* fmt, const Types&... args)
char* buffer = new char[std::snprintf(nullptr, 0, fmt, args...) + 1]; // +1 for \'\\0\'
std::sprintf(buffer, fmt, args...); // #6
stream << buffer;
delete[] buffer;
std::snprintf() 函数计算待输出字符串的长度,并依此长度开辟存放字符串的临时空间;然后由 std::sprintf() 函数将可变参数输出至临时空间中(#6),紧接着输出至文件流;最后释放临时空间。
以下是这四个函数的测试用例,
...
A("\\n%s won the %2dth FIFA World Cup!\\n", "Argentina", 22);
B("\\n%s uses %13s to shoot the %d eagles.\\n", "Bower", "Hoyt Highline", 2);
C("\\n%s is easy as pie!\\n", "Cxx");
D("\\n%s counted the money again. %4.2f dollars. That was all.\\n\\n", "Della", 1.87);
...
◆ 验证
在命令行中编译代码(-std=c++11),运行可执行文件并检查输出结果。以下是输出结果的部分内容,
$ g++ -std=c++11 variadic_printf.cpp
$ ./a.out
Argentina won the 22th FIFA World Cup!
Bower uses Hoyt Highline to shoot the 2 eagles.
$ cat variadic.output
Cxx is easy as pie!
Della counted the money again. 1.87 dollars. That was all.
$
◆ 最后
完整的代码请参考 [gitee] cnblogs/17390064 。
写作过程中,笔者参考了 获取va_list格式化长度。致作者 sdhongjun 。
受限于作者的水平,读者如发现有任何错误或有疑问之处,请追加评论或发邮件联系 15040298@qq.com。作者将在收到意见后的第一时间里予以回复。 本文来自博客园,作者:green-cnblogs,转载请注明原文链接:https://www.cnblogs.com/green-cnblogs/p/17390064.html 谢谢!
java-可变参数
/* 使用前提: 当前方法的参数的数据类型已经确定,但是参数的个数不确定,就可以使用可变参数 使用格式: 定义方法是使用 修饰符 返回类型 方法名(数据类型... 变量名){} 可变参数的原理: 可变参数底层就是一个数组,根据传递参数格式不同,会创建不同长度 的数组,来存储这些参数 传递的参数个数可以是0个和多个 注意事项: 一个方法的参数列表,只能有一个可变参数 如果方法的参数有多个,那么可变参数必须卸载参数列表的末尾 特殊写法: Object...obj */
public class Demo { public static void main(String[] args) { int i = add(1,1,2,3,4,4,4); // add()会创建一个长度为0的数组 System.out.println(i); } // 定义计算0-n个int整数的方法 // 已经知道数据类型为int,但是参数个数不确定 public static int add(int...arr){ int sum =0; System.out.println(arr);//[I@1b6d3586底层是一个数组 System.out.println(arr.length); for (int i :arr){ sum = sum +i; } return sum; } }
结果:
[I@1b6d3586
7
19
以上是关于可变参数的格式化输出的主要内容,如果未能解决你的问题,请参考以下文章