将 libfmt 与旧版 API 一起使用
Posted
技术标签:
【中文标题】将 libfmt 与旧版 API 一起使用【英文标题】:Using libfmt with a legacy API 【发布时间】:2020-08-03 10:21:44 【问题描述】:我想在旧版 C API 之上针对现代格式库(特别是 libfmt)测量 vsnprintf 的性能。不能直接在调用者处使用 C++。我该怎么做?
const char *fmt, ...
我们得到的参数并不意外地是一个格式字符串,后跟一个可变参数列表。输出需要以零终止。如果这无法获得最大性能,我将不得不手动实例化每个格式字符串的一个版本。现在我正在努力避免这种情况。
目标是具有提供的最大长度的缓冲区。我们不能将堆用于任何事情。没有堆。
【问题讨论】:
"不能在调用者处直接使用C++。" 嗯,什么意思?如果您使用 C++ 进行编程,使用 C++ 库,那么您如何不能够使用 C++? 使调用传递代码块中指定的参数的旧 API。也就是说,它是一个 C 可变参数列表。 C是调用者。我更新了问题正文以反映这一点。 您是说有 C 代码调用具有 C 可变参数接口的函数,并且该代码的实现是 C++?您想以某种方式处理 C 可变参数输入吗?嗯......你怎么知道参数是什么类型?fmt
的格式字符串,如果我没记错的话,不包含输入信息。
我通过检查我是否知道格式字符串来知道类型,如果我不知道,我可以调用 vsnprintf 作为后备。目标是查看 FMT_COMPILE 是否会在这种笨重的设置下提供性能优势,因为遗留代码现在并将继续使用 C。
【参考方案1】:
与 printf 相比,fmt 的工作方式有一个非常根本的区别。即 fmt 的格式化字符串不包含类型信息。
fmt
基于 C++ 可变参数模板。预计类型信息将按照 C++ 的典型方式进行传输:通过编译时 机制。因此,fmt
的格式字符串不需要重复所有格式化函数固有的类型信息。这种强类型允许fmt
允许基于类型的扩展功能。
C 变量删除所有类型信息。如果没有存储在字符串中的类型信息,就无法恢复 fmt
需要 完成其工作的类型信息。
libfmt 库包含一个 dynamic_format_arg_store
类型(这不是 C++20 的一部分,但我认为您可以构建它)。然而,即使这样也需要您知道在您存储参数时的类型。由于 C 可变参数已经删除了类型,所以你不走运。
fmt
作为库的基本假设使其与 C 可变参数不兼容。
【讨论】:
我同意你的观点,这是一个难题 - 但是我已经开始在传递给打印函数的字符串文字上“切换大小写”,这让我可以打开格式字符串。有了这个,我确实提前知道了类型。对于未处理的格式字符串,有一个后备到 vsnprintf。【参考方案2】:fmt 是一个 C++ 库,它不提供 C API,因此您需要使用 C++ 编译器或编写自己的 C 包装器。您可以使用dynamic_format_arg_store
在包装器中构建参数列表,但它的效率低于直接使用 C++ API。
【讨论】:
以上是关于将 libfmt 与旧版 API 一起使用的主要内容,如果未能解决你的问题,请参考以下文章
如何安装与旧版 TypeScript 兼容的 @types?
英特尔 oneAPI 与旧版 Parallel Studio XE 的优势(Fortran 用户)