2015-04-03 98 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建議的一個足夠大的緩衝區。