snprintf + Pebble

3
我正在为 Pebble 开发,并且遇到了一些困难。
我正在尝试用两个字符串和两个值填充一个 text_layer,就像这样:
WAIT AVG: 3 MAX: 5
由于 Pebble SDK 不支持 malloc,所以我不能使用 sprintf,因此我被迫使用 snprintf。以下代码只打印“4”:
srand(time(NULL));
int average = (rand()%6)+1; 
int maximum = average + 2;
static char *avgText="WAIT AVG: ";
static char *maxText="MAX: ";
snprintf(labelText,sizeof(avgText) + sizeof(average) + sizeof(maxText) + sizeof(maximum),"%s %d %s %d",avgText,average,maxText,maximum);

非常感谢您的帮助。我知道我可以创建4个单独的TextLayers,但这对我来说是最后的选择。

1
为什么sprintf依赖于malloc - Cory Nelson
@CoryNelson 说得对,snprintf 只需要一个额外的参数 n 来防止缓冲区溢出,因为 n 是要填充的最大缓冲容量。 - A Person
@Siidheesh 这太啰嗦了。根据标准,sizeof(char)保证为1 - Cory Nelson
@CoryNelson,这里是多余的,但是在他迁移到宽字符类型时包括 sizeof(所使用的类型) 是有用的:),不确定 Pebble SDK 是否支持宽字符。 - A Person
@CoryNelson - 我猜他们最初省略了sprintf以避免膨胀,然后在可疑的前提下屈服并添加了snprintf,以避免缓冲区溢出。但它并没有做到!https://dev59.com/dGct5IYBdhLWcg3wL6qi - Roddy
4个回答

10

你使用snprintf的方式不正确。

第二个参数(你试图计算的参数)是你要输出的字符数组的长度,而不是你要写入的字符数目。

像这样应该可以解决问题:

char labelText[64]; // Is this big enough?
snprintf(labelText, 64,"%s %d %s %d",avgText,average,maxText,maximum);

3

sizeof(avgText)sizeof(maxText)是指针的大小,而不是数组的大小。请参见例如这里。将您的代码更改为

static char avgText[] = "WAIT AVG: ";
static char maxText[] = "MAX: ";

为了将它们转换为数组。
编辑:
进一步说明,sizeof(average)average 在内部覆盖的字节数,而不是十进制表示占用的字节数。
编辑2:
正如 Roddy 的答案所说,计算我们想要的大小并将其作为实际缓冲区大小传递给 snprintf 是错误的。然而,如果有一个合理的上限(例如,在 32 位 int 中,10 个字节(不包括零终止符)总是足够的,但在您的用例中可能可以提供一个更低的上限),我们可以计算我们想要的大小:
char labelText [
        sizeof avgText - 1 + 10 +
        sizeof maxText - 1 + 10 + 3 + 1
];
/* sizeof avgText counts the 0-terminator, so does sizeof maxText, hence
the -1, two times 10 for the `int` (or any reasonable upper bound you have),
3 spaces and the 0-terminator. */

你甚至可以使用sprintf。使用snprintf,你可以做到:

snprintf(labelText, sizeof labelText,"%s %d %s %d", avgText, average, maxText, maximum);

HTH


你不需要这样做:没有必要在运行时计算输出字符串的长度。 - Roddy
@Roddy:我何时说过这样的话? - mafso
@maifso。我的观点是没有必要进行OP试图计算的(错误的)计算。输出的字符数并不重要,但缓冲区的大小是重要的。(请忽略我之前评论中的“在运行时”) - Roddy
是的,我在此期间看到了你的回答。请等一下,我很快就会编辑。 - mafso

1
请仔细阅读snprintf()man页面。它指出,第二个参数size用于引用要写入的字节数
在这里使用sizeof (avgText)sizeof(maxText)是行不通的。它们指的是指针的大小,而不是它所持有的数组长度。也许您想使用strlen()来获取字符串长度。

0

所以这个有效:

srand(time(NULL));
static char labelText[]="WAIT AVG: xxxxx MAX: xxxxxx";
int average = (rand()%6)+1; 
int maximum = average + 2;
static char avgText[]="WAIT AVG: ";
static char maxText[]="MAX: ";
snprintf(labelText,sizeof(labelText),"%s %d %s %d",avgText,average,maxText,maximum);
text_layer_set_text(waitField,labelText);

谢谢大家


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接