如果snprintf停在格式说明符的中间,如何继续?

时间:2015-04-03 19:17:03

标签: c printf

当输出缓冲区可能不足以容纳格式化字符串时,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库的解决方案都会这样做。

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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 time-(所以16个字节是不够的,但在你的情况下64个字节是合理的),并且只在极少数情况下重做它。如果可能,请使用asprintf

答案 2 :(得分:0)

您可以创建一个管道,使用fprintf在其中写入整个字符串,并使用第二个线程从管道中读取您喜欢的小块。这种方式fprintf函数将阻止并保存状态,直到您分派数据。

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