最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

天天视点!可变参数的格式化输出

来源:博客园

本文描述了将可变参数(variadic)按照格式化字符串的方式输出至标准输出(stdout)或文件流(ofstream)的一种实现方案,并加以了验证。

◆ 解法

通过可变参数函数(variadic function)和可变参数模板(variadic template),能够接受个数不定的参数。两种接受参数方式与两种输出目的地的组合,可以得到四种情况,

  • 可变参数函数输出至标准输出(A)
  • 可变参数模板输出至标准输出(B)
  • 可变参数函数输出至文件流(C)
  • 可变参数模板输出至文件流(D)

结合 *printf 系列输出函数以及变参标准库()中的宏定义和类型(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 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 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.outArgentina won the 22th FIFA World Cup!Bower uses Hoyt Highline to shoot the 2 eagles.$ cat variadic.outputCxx is easy as pie!Della counted the money again. 1.87 dollars. That was all.$

◆ 最后

完整的代码请参考 [gitee] cnblogs/17390064 。

写作过程中,笔者参考了 获取va_list格式化长度。致作者 sdhongjun 。

关键词: