2011-09-09 46 views
3

我正在爲PHP編寫一個C擴展,在那裏我必須建立一個基於一些子串的字符串。目前看起來像這樣:串聯字符串 - 你如何以一種乾淨的方式來做這件事?

spprintf(
    &bucket_list_url, 
    strlen(host) + 1 + sizeof(port) + 1 + strlen(prefix) +strlen("?buckets=true"), 
    "%s:%d/%s?buckets=true", 
    host, 
    port, 
    prefix 
); 

它的工作,但看起來很可怕,可能難以維護。是否有更簡潔的方式將這些字符串安全地連接在一起?

我在C初學者,因爲你可能已經注意到了,所以我不能拿出任何清潔的解決方案爲止。

回答

3

如果您使用的GNU C運行庫(glibc的),你可以使用asprintf(3)函數將字符串格式化爲一個動態分配的緩衝區。這樣,你不必擔心有足夠大的緩衝區。例如:

// Error checking omitted for expository purposes 
char *bucket_list_url; 
asprintf(&bucket_list_url, "%s:%d/%s?buckets=true", host, port, prefix); 
... // do stuff 
free(bucket_list_url); 

如果你不使用的glibc,你仍然可以使用snprintf(3),但你必須在緩衝區長度猜測。如果你猜錯了,你必須分配一個更大的緩衝區並重試。

+0

HM,看起來好多了,會試試看,感謝 – Max

+0

有了'snprintf'你能猜到一次,但如果失敗,則不要「再試一次」,因爲它告訴你它需要多少空間。 (當然,你總是可以用'snprintf(NULL,0,...)'拋出你的第一個猜測,但也許對於給定的情況,你可以對你可能需要的東西進行有根據的猜測並且節省一些週期。) –

0

我想你的意思使用的snprintf:

char bucket_list_url[1024]; 

snprintf(bucket_list_url, sizeof(bucket_list_url), "%s:%d/%s?buckets=true", host, port, prefix); 

的snprintf的第二個參數是第一個參數的字節長度,而不是你期待的函數調用後得到的字符串的長度。

0

這是我寫回來的小片段。這可能有點愚蠢,但也許這就是你要找的。注意:這不是最高效的,因爲它有兩個vsnprintf s。首先是確定緩衝區的長度應該是多少。

 

char * new_string_from_format(const char * fmt, ...) { 
    int size; 
    char * string_buffer; 

    assert(fmt != NULL); 
    assert(strlen(fmt) > 0); 

    // first determine the length the buffer should be 
    va_list args; 
    va_start(args, fmt); 
    size = vsnprintf(NULL, 0, fmt, args) + 1; 
    va_end(args); 
    assert(size > 0); 


    string_buffer = new char[size]; 
    va_start(args, fmt); 
    vsnprintf(string_buffer, size, fmt, args); 
    va_end(args); 

    return string_buffer; 
} 

 

這也可能是類似的glibc的asprintf,(但不要求的glibc)

+1

The問題被標記爲C,而不是C++。你可能想要清理一下。 (如果你的C(或C++)編譯器支持一些C99特性,可以使用'v'版本並使用'va_copy'而不是'va_end' /'va_start')(使用它會更有效率'std :: string :: reserve'並使用'std :: string'的緩衝區而不是自己把它扔掉?) –

+0

好點;我拿出了C++。並感謝其他建議。我會考慮將它們添加到我自己的代碼中,如果一切順利,我會更新它。 – Tom

相關問題