2015-11-16 85 views
1

printf是一個非常漂亮的函數,因爲它可以幫助您以非常乾淨的方式格式化字符串。連接字符串像printf

printf("Player %s has lost %d hitpoints", victim.name, damage); 

有沒有類似的方式來連接,並在一個「正常的字符串」像下面執行強制:

uint8_t myString = ("Player %s has lost %d hitpoints", victim.name, damage); //SOMETHING LIKE THIS 
+4

'的sprintf()'是你的答案 – Haris

+3

你想要['sprintf的()'](http://linux.die.net/man/3/sprintf)? –

+1

您可能會發現約翰卡馬克的這個功能有趣,如在Quake 3引擎中實現的:https://github.com/id-Software/Quake-III-Arena/blob/master/code/splines/q_shared.cpp( 700行)。請注意,您需要足夠深的緩衝區或嵌套調用會發生有趣的事情,當然,如果您正在編寫多線程代碼,這是一個很大的禁忌。 – szczurcio

回答

4

C99的snprintf打印到一個字符串,並保證不溢出緩衝區:

char msg[48]; 

snprintf(msg, sizeof(msg), 
    "Player %s has lost %d hitpoints", victim.name, damage); 

snprintf返回,將已被寫入了該字符串已經足夠大的字符數。因此,如果返回的值等於或大於緩衝區大小,則字符串將被截斷。

它是合法的,通過零緩衝區大小和一個空指針,這樣就可以通過使探測通話先做好自己的分配:

char *msg; 
int n; 

n = snprintf(NULL, 0, 
    "Player %s has lost %d hitpoints", victim.name, damage); 

msg = malloc(n + 1); 
n = snprintf(msg, n + 1, 
    "Player %s has lost %d hitpoints", victim.name, damage); 

// do stuff with msg 

free(msg); 

在GNU編譯器,非sandard功能asprintf會爲你做:

char *msg = asprintf("Player %s has lost %d hitpoints", 
    victim.name, damage); 

// do stuff with msg 

free(msg); 
5

您可以使用sprintf()。像這樣

char* myString = malloc(50); 

sprintf(myString, "Player %s has lost %d hitpoints", victim.name, damage); 

正如你能猜到,它代表了字符串的printf


請注意sprintf()需要char*,不uint8_t


Offcourse您還可以使用snprintf()。增加的優點是可以將字符數複製到字符串中。這可以防止緩衝區溢出。

char* myString = malloc(50); 

snprintf(myString, 50, "Player %s has lost %d hitpoints", victim.name, damage); 
+2

如果可能,請使用'snprintf'。 – user694733

+0

@ user694733,thanx .. added .. :) – Haris

+0

@Haris值得指出的是,在你的例子中,snprintf只會寫49個字符。一個總是保留爲空終止符。 – Magisch

2

嘗試這樣

char str[MAX_LEN]; 
    sprintf(str,"Player %s has lost %d hitpoints", victim.name, damage); 

,但我不知道它是非常安全的傳遞uint8_t*sprintf,而不是char *。 (可能違反約束條件,關於類似情況的更多細節,請參見here)。

事實上,爲了更安全,您還可以使用snprintf

+0

如果可能,請使用'snprintf'。 – user694733

+0

@ user694733你的意思是因爲你可以指定寫入的最大字節數? – Magisch

+0

@Magisch是的,防止溢出。 – user694733

2
printf("Player %s has lost %d hitpoints", victim.name, damage); 

如果你希望將結果保存在一個字符串而不是打印出來,也可以從同一個家族,稱爲sprintf另一個功能。在你的情況下,使用這樣的:

sprintf(myString,"Player %s has lost %d hitpoints", victim.name, damage); 

Further info on sprintf

由於user694733指出,通常使用更安全snprintf而不是sprintf。兩者的區別在於,對於snprintf你到指定字符的最高金額寫入到一個字符串(這包括在第二個參數終止字符\0!」。More info on snprintf

+0

如果可能,請使用'snprintf'。 – user694733

+0

@ user694733我添加了一個符號,用我的答案來討論這個問題。 – Magisch

4

每個人都暗示sprintf,但在我看來,這是更好始終使用snprintf函數原型如下:

int snprintf (char * s, size_t n, const char * format, ...); 

第一個參數是你的字符串緩衝區,第二個參數是它的最大容量,其次是一個格式說明字符串和參數。用法示例:

char str[STR_LEN]; 
snprintf(str, sizeof(str), "Player %s has lost %d hitpoints", victim.name, damage); 

注意的是,雖然這不會做任何違法的事情(使用sprintf你可能產生不確定的行爲),如果你的緩衝區不夠長的字符串將被截斷,這可能導致一些令人吃驚的輸出。最好是檢查snprintf的結果,看看有多少個字符是真正寫入的(感謝chux指出了這一點)。

如果你有興趣能夠編寫代碼就像一個在你的問題,這裏的字符串是返回你從格式化功能,您可能會發現卡馬克的va從他idTech3引擎有趣:https://github.com/id-Software/Quake-III-Arena/blob/master/code/splines/q_shared.cpp ( 700行)。請注意,您應該瞭解這是如何工作的以及它對嵌套調用的可能影響,不要提到如果您在多線程環境中使用此問題可能會出現的問題。

+1

除非檢查到'snprintf()'的結果,否則使用'sprintf()'溢出緩衝區的UB現在有可能使代碼繼續從snprintf()中截取緩衝區。否則輸出可能是''播放器long_name丟失了''。最好查看返回值。 – chux

+1

@chux好,趕快,謝謝。 – szczurcio