avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] sprintf


From: Dave Hylands
Subject: Re: [avr-gcc-list] sprintf
Date: Thu, 26 Feb 2009 17:20:21 -0800

Hi Dave,

> So I was using sprintf to create some data to send to the LCD, by way of
> lcd_puts.
> I had a pair of arrays, A_String[17], and B_String[17] which I filled
> using two loops.
>
> I hit some problems when I tried to consolidate this into one loop.
> The symptom was that the second string wouldn't display, but it would if I
> had the two routines in separate loops.
> I'm creating a simple bar graph, Data_A and Data_B have some value that is
> roughly between 0 and 16* the Step value.
>
>   for (i=0; i<16; i++)
>   {
>    if ((Step * i) < Data_A) {
>     sprintf((A_String+i), "%c", 0xFF);
>    } else {
>     sprintf((A_String+i), "%c", 0x20);
>    }
>    if ((Step * i) < Data_B) {
>     sprintf((B_String+i), "%c", 0xFF);
>    } else {
>     sprintf((B_String+i), "%c", 0x20);
>    }
>   }

Wow - using sprintf to write single character values is an awfully
expensive way of doing things.

I would have coded:

  for (i=0; i<16; i++)
  {
   if ((Step * i) < Data_A) {
     A_String[i] = 0xFF;
   } else {
    A_String[i] = 0x20;
   }
   if ((Step * i) < Data_B) {
    B_String[i] = 0xFF;
   } else {
    B_string[i] = 0x20;
   }
  }
  A_String[16] = 0;
  B_String[16] = 0;

>
>   lcd_home();
>   lcd_gotoxy(0,0);
>   lcd_puts(A_String); // String must be null terminated.
>   lcd_gotoxy(0,1);
>   lcd_puts(B_String);
> In the above implementation, B_String would not show up on the display, but
> A_String would..
>
> Below is the version that worked, the only difference is that the A string
> is completed before starting on the B string.
>
>   for (i=0; i<16; i++)
>   {
>    if ((Step * i) < Data_A) {
>     sprintf((A_String+i), "%c", 0xFF);
>    } else {
>     sprintf((A_String+i), "%c", 0x20);
>    }
>
>   for (i=0; i<16; i++)
>   {
>    if ((Step * i) < Data_B) {
>     sprintf((B_String+i), "%c", 0xFF);
>    } else {
>     sprintf((B_String+i), "%c", 0x20);
>    }
>   }
>
> It turned out that I had neglected to allow for the terminating null in the
> strings, but this raises two questions for me.
>
> 1: Why doesn't sprintf((A_String+16), "%c", 0x00); drop a null into the last
> element of A_String.

This will actually drop two characters. The null character for the %c
and a terminating null character.

sprintf( foo, "%c", 'A' );

will write the A followed by a null character. So each time through
the loop you're actually writing two characters. As you discovered the
arrays need to be sized appropriately to deal with this.

> 2: Why does the separate loops case work at all?

It probably depends. The order of A_String and B_String relative to
each other and the exact size probably makes a difference. If you only
declared A_String as a 16 element array and you did

sprintf( A_String + 15, "%c", 0x20 );

then this will write the 0x20 to A_String[15] and 0x00 to
A_String[16], which will trample the byte beyond the end of A_String,
which might have been the beginning of B_String. So if you looped
writing A_String first, it would trample B_String, but the second loop
writing B_String would have fixed B_String[0] back up.

Then you amalgamated the loops, A_String[16] was trampled after
B_String[0] was written, so things didin't get corrected.

> I solved my problem by inserting the null with
>  memset((A_String+16), 0, 1); and the same for B_String.

A_String[16] = 0;

would be a much more efficient way of performing the same operation.

-- 
Dave Hylands
Shuswap, BC, Canada
http://www.DaveHylands.com/




reply via email to

[Prev in Thread] Current Thread [Next in Thread]