2016-03-03 82 views
0

我正在使用vsprintf从格式生成一个字符串,并且在记录之前需要预先查找预先安排的字符串。下面的代码打印格式字符串,但我会如何预先给另一个字符串呢?理想情况下,以相当有效的方式。使用vsprintf预先填充字符串到另一个格式字符串的一种有效方法

例如,如果我叫这样的:

LOG(SYSTEM1, DEBUG, "number=%d, string=%s\n", 1, "Hi"); 

我会看到印:

SYSTEM1 number=1, string=Hi 

到目前为止的代码:

#include <stdio.h> 
#include <stdarg.h> 

#define EMERGENCY  0 
#define ERROR   1 
#define WARN   2 
#define INFO   3 
#define DEBUG   4 

enum SubSystemID { SYSTEM1, SYSTEM2, SYSTEM3, SYSTEM4 }; 

void LOG(enum SubSystemID id, unsigned long severity, const char* format, ...) { 
    static const char* chaTypes[] = { 
     "SYSTEM1", "SYSTEM2", "SYSTEM3", "SYSTEM4" }; 

    char buffer[256]; 
    va_list args; 
    va_start (args, format); 
    vsprintf(buffer, format, args); 

    // Code here to send a char* string to a logging system 
    printf(buffer); 

    va_end (args); 
} 
+0

为什么不使用最后的'printf'来进行连接?数组应该是'static const char * const chaTypes []',否则表本身不是'const'。 – Olaf

+0

@Olaf这太容易了。然而我怀疑'printf(buffer);'是真正的“发送char *字符串到日志系统”的占位符。 – chux

+0

@Olaf由chux建议,printf(buffer)确实是一个将字符串发送到日志系统的占位符 –

回答

1

你可以尝试: -

strcpy (buffer, chaTypes [id]); 
vsprintf (&buffer [strlen (buffer)], format, args); 

,或者你可以预先计算strlen的一部分使其整数数组: -

static int [] lengths = null; 

if (lengths == null) 
{ 
    lengths = malloc (sizeof (int), sizeof chaTypes/sizeof chaTypes [0]); 
    foreach string 
    lengths [i] = strlen (chaTypes [i]); 
} 
+1

是'foreach string'伪代码还是C的一些新味道? – chux

+0

是的,这是伪代码。 – Skizz

0

如果你的目的是为了避免格式化我会用的fwrite()和发送任何你想要的文件句柄。如果你想使用一些其他的设施,那么你可能想拥有某种通用输出字符串函数,然后通过它输出你的日志语句。

例如:

void writeLogString(const char *str, int len) 
{ 
#ifdef _WIN32 
    OutputDebugStringA(str); 
#else 
    fwrite(str, sizeof(char), len, stdout); 
#endif 
} 

void vlogf(enum SubSystemID id, unsigned long severity, const char *format, va_args args) 
{ 
    const char *chaTypes[] = { "SYSTEM1", "SYSTEM2", "SYSTEM3", "SYSTEM4" }; 

    char buffer[256]; 
    int len = vsnprintf(buffer, sizeof(buffer), format, args); 

    writeLogString(chaTypes[id], strlen(chaTypes[id])); 
    writeLogString(" ", 1); 
    writeLogString(buffer, len); 
} 

void logf(enum SubSystemID id, unsigned long severity, const char *format, ...) 
{ 
    va_list args; 
    va_start(args, format); 
    vlogf(id, severity, format, args); 
    va_end(args); 
} 

一般来说我会确保我的日志记录工作首先是因为它通常是到调试应用程序非常关键。

如果您遇到速度问题,那么无论您尝试做什么,printf()都会导致性能下降。如果您确实需要加速生产环境中的日志记录,则可能需要考虑使用某些宏,以便在禁用严重性时甚至不调用格式化函数。

编辑:A working example here with some tests

1

代码可以重新写入格式。

// concatenate in some fashion. 
char *prefix = chaTypes[id]; // chaTypes[] must not contain % 
size_t len1 = strlen(prefix); 
size_t len2 = strlen(format) + 1; 
char newformat[len1 + len2]; 
memcpy(newformat, prefix, len1); 
memcpy(&newformat[len1], prefix, len2); 

vsprintf(buffer, newformat, args); 

然而@Skizzstrcpy()想法是很难被击败。

+0

我使用malloc()和/或strcpy()看到的问题是,vsprintf()已经为你做到了这一点,所以你避免了额外拷贝的惩罚。一个拷贝到你已经分配的任何内存字符串,那么另一个来自vsprintf()本身。 – Kelmar

+0

@Kelmar关注“使用malloc()和/或strcpy()”。这个答案不使用'malloc()'和'strcpy()'。此外,'vsprintf()'不知道调用'malloc()',因此关于'malloc()'的注释不清楚。此外,与处理格式字符串的处理的陷阱相比,复制字符串性能微不足道。 – chux

+0

对不起,你对内存分配是正确的。 如果vprintf()为你做了这些事情,那么为什么还要做所有的工作? – Kelmar

相关问题