2015-11-16 48 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