2015-04-03 99 views
0

当输出缓冲区可能不足以容纳格式化的字符串时,snprintf函数是完美的。但是如果由于缓冲区长度不足而导致snprintf的呼叫停止,如何继续打印到另一个缓冲区?如果snprintf在格式说明符中停止,如何继续?

char buf1[16] = {0}; 
char buf2[16] = {0}; 
int n = snprintf(buf1, sizeof buf1, "Lorem ipsum %d dolor sit", 123456); 
assert(strcmp(buf1, "Lorem ipsum 123") == 0); // ok 

// Insert solution here 

assert(strcmp(buf2, "456 dolor sit") == 0); // expected result 

P.S.我没有对snprintf感兴趣,任何限于标准C库的解决方案都可以。

+0

你有没有研究过'n'值? – 2015-04-03 19:19:23

+0

@MooingDuck当然,这就是为什么我把它放在片段中。我知道成语首先用'n = 0'调用'snprintf'来确定长度,然后分配足够大小的缓冲区,然后进行真正的打印。我的问题是,是否有一种方法可以在不分配额外缓冲区的情况下从'snprintf'停止的地方恢复。 – 2015-04-03 19:33:38

回答

2

阅读snprintf(3)的文档。它返回所需字符的总数(你甚至可以调用它的大小为0的NULL缓冲区以获得所需字符的数量)。在使用Gnu glibc的Linux上,您也可以使用asprintf(3)

所以,你可能代码:

int nbc = snprintf(buf1, sizeof(buf1), 
    "Lorem ipsum %d dolor sit", 123456); 
if (nbc<sizeof(buf1)) 
    behappywith(buf1); 
else { 
    memset(buf2, 0, sizeof(buf2)); 
    char* dynbuf = malloc(nbc+1); 
    if (!dynbuf) { perror("malloc dynbuf"); exit(EXIT_FAILURE); }; 
    snprintf(dynbuf, nbc+1, 
      "Lorem ipsum %d dolor sit", 123456); 
    strncpy(buf2, dynbuf+sizeof(buf1), sizeof(buf2)); 
    buf2[sizeof(buf2)-1] = '\0'; 
    free (dynbuf); 
    behappywithboth(buf1,buf2); 
} 

在实践中,这是更好地调用snprintf有一个相当大的足够的缓冲区以诚通常避免调用malloc然后snprintf一个时间(所以16字节是不够的,但在你的情况下64个字节本来是合理的),并且只在极少数情况下重做。如果可能的话,使用asprintf

+0

'buf2'在字符串不匹配的情况下需要空终止代码 – 2015-04-03 19:57:21

3

没有。 snprintf是无状态的,它不能简单地“恢复”它停止的地方。最接近的是分配一个更大的缓冲区,打印整个消息,然后将所需的子字符串strcpy到目标缓冲区。

char buf1[16] = {0}; 
char buf2[16] = {0}; 
int n = snprintf(buf1, sizeof(buf1), "Lorem ipsum %d dolor sit", 123456); 

if (n > 15) { 
    char* t = malloc(n+1); 
    if (t) { 
     n = snprintf(t, n, "Lorem ipsum %d dolor sit", 123456); 
     strncpy(buf2, t+sizeof(buf1)-1, sizeof(buf2)-1); 
     free(t); 
    } 
    //might fail the subsequent assert if malloc failed 
} 

assert(strcmp(buf1, "Lorem ipsum 123") == 0); // ok 
assert(strcmp(buf2, "456 dolor sit") == 0); // expected result 
+0

对'malloc'的失败缺少测试 – 2015-04-03 19:27:47

+0

@BasileStarynkevitch:谢谢。我习惯于C++,我不必那样检查。 – 2015-04-03 19:30:08

+0

这应该包括代码来空终止'buf2'(这个特定的字符串适合缓冲区,但如果使用更长的字符串会出现问题) – 2015-04-03 19:56:31

0

您可以创建一个管道,使用fprintf写全串在那里,并使用第二个线程从管道与小块,只要你喜欢阅读。这种方式fprintf函数将阻塞并保存状态,直到您分派数据。

实现显然不适合您的模板,但如果您的数据太大而无法放入单个内存缓冲区中,则必须同时生成和分派数据。否则,只需分配一个像Mooing Duck建议的一个足够大的缓冲区。