printf-我可以将所有可变参数作为指针而不是在堆栈上一一传递吗?

时间:2018-08-08 08:57:38

标签: c printf

我有一个二进制日志系统,该系统在运行时仅将可变参数printf参数有效地写入文件,然后对其进行后期处理以生成文本日志。

我生成文本日志的后处理工具需要将每个printf参数读入一个变量,只是这样它才能在堆栈上传递给printf。

例如,生成用于调用的文本:

my_binary_printf("here's an int: %d, here's a float %f, here's a char: %c", i, f, c);

从保存运行时的int,float和char的二进制文件开始, 我需要做类似的事情:

char *binary_data;  // mmap-ed from the binary file produced at runtime
int param0 = *((int*) &(binary_data[0]));
float param1 = *((float*) &(binary_data[4]));
char param2 = *((char*) &(binary_data[8]));
printf(the_format_string, param0, param1, param2);

有没有一种方法可以将所有printf参数作为指向数据的指针?喜欢:

cool_printf(the_format_string, binary_data);

我希望获得这种解决方案的动机是由于数据复制较少,因此后期处理速度更快。

我现在不需要支持具有不同字节序的计算机。

如果它具有我想要的功能,我非常愿意使用其他打印库(例如fastformat或Boost的功能)。

1 个答案:

答案 0 :(得分:4)

一种解决方案将涉及编写您自己的格式字符串解析器,该解析器解释要从二进制Blob中提取的具有数据宽度的格式说明符,以使每个格式说明符都会导致数据索引增加,并提取并打印正确的类型

功能vprintf表面上看起来很接近您需要的功能,但不可行。它只需要一个va_list参数,通常使用...va_start的var-arg列表中创建,但是在您的情况下,输入的不是var-arg列表,因此在没有先解压缩二进制数据的情况下,不太可能直接对二进制数据进行操作-除了运气不好以外,甚至肯定不是便携式的。

vprintf的(或至少一个)问题是一个var-arg列表,不太可能以与二进制blob相同的方式对齐;堆叠的参数可能具有固定的对齐方式,并且不是连续的。

我在这里建议的方法是解析格式字符串,直接打印每个非格式说明符字符,完全提取格式说明符(使用所有修饰符),从说明符中确定宽度/类型,然后将大量数据提取到适当的数据类型,使用 whole 格式说明符打印单个数据项,然后按宽度增加数据索引。像这样继续整个格式字符串。这是很多工作-您必须做很多这样的工作才能证明工作的合理性-但您只需编写一次即可,而且它是通用的,因此可以简化维护工作。

注意:

  

我希望获得这种解决方案的动机是由于数据复制较少,因此后期处理速度更快。

那是一个糟糕的原因;它对性能的影响可以忽略不计。通过在格式字符串中编码二进制Blob的任意数据结构的简便性,可以更好地证明这一点。如果您有很多这样的代码,并且要编码许多不同的数据结构,那么这可能会对开发,可读性和维护性产生重大影响。