3

I'm developing for Pebble and I'm off to a rough start.

I'm trying to populate a text_layer with 2 strings and 2 values, something like this:

WAIT AVG: 3 MAX: 5

Since malloc is not supported in Pebble SDK, I can't use sprintf, hence I'm stuck with snprintf. The following code only prints "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);

Any help would be greatly appreciated. I know that I can create 4 separate TextLayers but that's kind of a last resort for me.

Charles
  • 50,943
  • 13
  • 104
  • 142
gh0st
  • 214
  • 3
  • 15
  • 1
    Why does `sprintf` depend on `malloc`? – Cory Nelson Jan 08 '14 at 15:03
  • @CoryNelson has a point, snprintf only takes an extra param `n` to prevent buffer overflows, as `n` is max buffer capacity to fill – A Person Jan 08 '14 at 15:05
  • @Siidheesh That's just overly verbose. `sizeof(char)` is guaranteed to be `1` by the standard. – Cory Nelson Jan 08 '14 at 15:05
  • @CoryNelson, it is redundant here, but it's useful to include `sizeof(the type used)` in case he migrates to a wide char type :), not sure if the Pebble SDK supports wide chars though – A Person Jan 08 '14 at 15:07
  • @CoryNelson - I guess they initially omitted `sprintf` to avoid bloat, and then relented and added `snprintf` on the dubious premise of avoiding buffer ovverruns. Which it doesn't! http://stackoverflow.com/questions/12275381/strncpy-vs-sprintf – Roddy Jan 08 '14 at 15:46

4 Answers4

10

You're just using snprintf wrong. ;-)

The second parameter (which you're trying to calculate, badly) is the length of the character array that you're printing into, not the number of characters you're trying to write.

Something like this should work:

char labelText[64]; // Is this big enough?
snprintf(labelText, 64,"%s %d %s %d",avgText,average,maxText,maximum);
tympaniplayer
  • 171
  • 2
  • 19
Roddy
  • 66,617
  • 42
  • 165
  • 277
3

sizeof(avgText) and sizeof(maxText) are sizes of pointers, not array sizes. See e.g. here. Change your code to

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

in order to make them arrays.

edit:

Further note, that sizeof(average) is the size in bytes average covers internally, not how many bytes a decimal representation would consume.

edit2:

As Roddy's answer says, it's wrong to calculate the size we want to have and pass that size to snprintf as an actual buffer size. We can, however, calculate the size we want to have provided there is a reasonable upper bound (e.g. with 32 bit int, 10 bytes (without 0-terminator) are always sufficient, but maybe you can give a lower upper bound in your use case):

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. */

and you could even use sprintf. With snprintf, you can do:

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

HTH

Community
  • 1
  • 1
mafso
  • 5,433
  • 2
  • 19
  • 40
  • You don't need to do this: There's no need to calculate the output string length at run-time. – Roddy Jan 08 '14 at 15:13
  • @Roddy: Where did I say so? – mafso Jan 08 '14 at 15:14
  • @maifso. My point is there's no need to do the (faulty) calculation that the OP is attempting. The no. of characters to be output is not important, but the size of the buffer *is*. (Ignore 'at runtime' in my earlier comment) – Roddy Jan 08 '14 at 15:22
  • Yes, I've seen your answer in the meanwhile. Wait a minute, I'll edit soon. – mafso Jan 08 '14 at 15:25
1

read the man page of snprintf() properly. it says, the second argument size is used to refer to the number of bytes to be written.

sizeof (avgText) and sizeof(maxText)is not gonna work here. It refers to the size of the pointer, not the length of the array it holds. Maybe you want to use strlen() for the string length.

Natasha Dutta
  • 3,242
  • 21
  • 23
0

So this worked:

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);

thanks guys

gh0st
  • 214
  • 3
  • 15