在C中,是否可以转发可变参数函数的调用?如,
int my_printf(char *fmt, ...) {
fprintf(stderr, "Calling printf with fmt %s", fmt);
return SOMEHOW_INVOKE_LIBC_PRINTF;
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,以上述方式转发调用显然不是必需的(因为你可以用其他方式记录调用,或者使用vfprintf),但是我正在处理的代码库要求包装器做一些实际的工作,并且没有没有(并且不能添加)类似于vfprintf的辅助函数.
[更新:基于迄今为止提供的答案,似乎存在一些混淆.用另一种方式表达问题:通常,你可以包装一些任意的可变参数函数而不修改该函数的定义.
我有一个类,它包含一个"错误"函数,可以格式化一些文本.我想接受可变数量的参数,然后使用printf格式化它们.
例:
class MyClass
{
public:
void Error(const char* format, ...);
};
Run Code Online (Sandbox Code Playgroud)
Error方法应该接受参数,调用printf/sprintf来格式化它然后用它做一些事情.我不想自己编写所有格式,因此尝试找出如何使用现有格式是有意义的.
我的程序写入日志和stdout.但是,每条消息都有一定的优先级,用户在Preferences中指定哪个优先级转到哪个流(log或stdout).
unsigned short PRIO_HIGH = 0x0001;
unsigned short PRIO_NORMAL = 0x0002;
unsigned short PRIO_LOW = 0x0004;
Run Code Online (Sandbox Code Playgroud)
首选项由一些标志处理:
unsigned short PRIO_LOG = (PRIO_HIGH | PRIO_NORMAL);
unsigned short PRIO_STD = (PRIO_HIGH);
Run Code Online (Sandbox Code Playgroud)
该write_log函数应使用与printf函数相同的参数,并添加参数unsigned short priority.
write_log((PRIO_NORMAL|PRIO_LOW), "HELLO %s, take %d", "World", 1);
Run Code Online (Sandbox Code Playgroud)
(即使PRIO_NORMAL|PRIO_LOW没什么意义......)
检查标志很简单:( if(priority & PRIO_LOG)如果在两个参数中都设置了任何标志,则返回> 1)
但是,我不知道如何将字符串文字和格式参数传递给printf函数.任何人都可以帮助或给我一个指针(可能的替代方法可以实现相同的效果)?非常感谢.
我的目标是在OSX环境中的QT项目中使用C++解析大型csv文件.(当我说csv我的意思是tsv和其他变种1GB~5GB).
这似乎是一项简单的任务,但是当文件大小变大时,事情会变得复杂.我不想编写自己的解析器,因为许多边缘情况与解析csv文件有关.
我已经找到了各种csv处理库来处理这个工作,但解析1GB文件在我的机器上大约需要90~120秒,这是不可接受的.我现在没有对数据做任何事情,我只是为了测试目的而处理和丢弃数据.
cccsvparser是我尝试过的库之一.但唯一足够快的库是fast-cpp-csv-parser,它给出了可接受的结果:我的机器上15秒,但只有在知道文件结构时它才有效.
使用示例:fast-cpp-csv-parser
#include "csv.h"
int main(){
io::CSVReader<3> in("ram.csv");
in.read_header(io::ignore_extra_column, "vendor", "size", "speed");
std::string vendor; int size; double speed;
while(in.read_row(vendor, size, speed)){
// do stuff with the data
}
}
Run Code Online (Sandbox Code Playgroud)
如你所见,我无法加载任意文件,我必须专门定义变量以匹配我的文件结构.我不知道任何允许我在运行时动态创建这些变量的方法.
我尝试过的另一种方法是逐行读取csv文件,使用fast-cpp-csv-parser, LineReader类非常快(读取整个文件大约需要7秒),然后使用可以处理字符串的cccsvparser lib 解析每一行.但这需要大约40秒才能完成,与第一次尝试相比这是一个改进,但仍然是不可接受的.
我已经看到了与csv文件解析相关的各种stackoverflow问题,它们都没有将大文件处理到帐户中.
此外,我花了很多时间谷歌搜索找到这个问题的解决方案,我真的很想念包裹经理喜欢npm或pip在搜索开箱即用的解决方案时提供的自由.
我将不胜感激任何有关如何处理此问题的建议.
编辑:
当使用@fbucek的方法时,处理时间减少到25秒,这是一个很大的改进.
我们可以进一步优化这个吗?
我试图在运行时为函数调用生成一个参数列表,但我想不出在c ++中实现这一点的方法.
这是我写的助手库.我通过网络从客户端获取输入数据,并使用该数据调用用户先前设置的函数指针.该函数采用一个字符串(类似于printf的标记)和不同数量的参数.我需要的是根据从客户端收到的数据添加更多参数的方法.
我将函数存储在函数指针的映射中
typedef void (*varying_args_fp)(string,...);
map<string,varying_args_fp> func_map;
Run Code Online (Sandbox Code Playgroud)
一个示例用法是
void printall(string tokens, ...)
{
va_list a_list;
va_start(a_list, tokens);
for each(auto x in tokens)
{
if (x == 'i')
{
cout << "Int: " << va_arg(a_list, int) << ' ';
}
else if(x == 'c')
{
cout << "Char: " << va_arg(a_list, char) << ' ';
}
}
va_end(a_list);
}
func_map["printall"] = printall;
func_map["printall"]("iic",5,10,'x');
// prints "Int: 5 Int: 10 Char: x"
Run Code Online (Sandbox Code Playgroud)
当硬编码函数调用及其参数时,这很好用,但如果我收到了数据"CreateX 10 20",程序需要能够自己调用参数.例如
// func_name = "CreateX", tokens …Run Code Online (Sandbox Code Playgroud) void myPrintf(const char* format, ...) {
// some code
va_list vl;
printf(format, vl);
}
int main() {
myPrintf("%d\n", 78);
}
Run Code Online (Sandbox Code Playgroud)
在这段代码中,我试图将参数从省略号传递给printf.它编译但打印垃圾而不是78.这是正确的方法吗?
我有一个函数,log_message它需要可变参数。
log_message(int level, char *fmt, ...)
Run Code Online (Sandbox Code Playgroud)
现在在调用 this( log_message) 函数之前,我必须添加新函数 ( _log_message),新函数将调用log_message.
_log_message(int level, char *fmt, ...)
Run Code Online (Sandbox Code Playgroud)
新功能也一样。何时_log_message调用log_message它会将变量输入转换为va_list. 现在我有va_list,我不想改变原来的,有没有办法改回可变输入,所以我可以调用原来的(log_message)。
我想编写一个带有省略号参数的函数 writelog() ,它应该将相同的省略号参数转发给另一个函数。怎么做?
我的函数示例:
void writetolog(char *format, ...)
{
FILE *file;
if ((file = fopen(LOG_FILE, "a")) != NULL)
{
fprintf(file, format, ...);
fclose(file);
}
}
Run Code Online (Sandbox Code Playgroud)
函数 fprintf() 应该具有与函数 writetolog() 相同的省略号参数。