Author Topic: C function like printf but not sending to stdout? (XC8)  (Read 39201 times)

0 Members and 1 Guest are viewing this topic.

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #25 on: March 12, 2013, 03:34:35 am »
Code: [Select]
lcd_out(&temp);

Ooh, missed this one. Bad, very bad. You're taking the address of the char to use it like a pointer. The problem is that C strings contain an end-of-string marker one past the last character, which doesn't exist because this is just a single char variable, so it's looking somewhere in God-knows-where in your memory for it. You got lucky.

The worst part is that there is absolutely no way for the compiler to detect it. A memory analyzer like Valgrind would scream bloody murder at the sight of it, but you can't exactly use Valgrind on an 8-bit microcontroller.
« Last Edit: March 12, 2013, 03:37:07 am by c4757p »
No longer active here - try the IRC channel if you just can't be without me :)
 

Online IanB

  • Super Contributor
  • ***
  • Posts: 11790
  • Country: us
Re: C function like printf but not sending to stdout? (XC8)
« Reply #26 on: March 12, 2013, 03:36:56 am »
I vastly prefer using '0' to 0x30 in that case - more obvious.

Good point. I was going with 0x30 because that is what was given, but the improved version would look like this:

Code: [Select]
    int versionMajor = 1;
    int versionMinor = 5;

    char buf[] = "Version x.y";

    buf[8] = '0' + versionMajor;
    buf[10] = '0' + versionMinor;

(Note the single quotes around the '0', not double quotes. The single quotes turn the character into its ASCII value.)
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #27 on: March 12, 2013, 03:38:48 am »
Doing it this way:

Code: [Select]
strcpy(lcd_buffer,"Version x.y");
lcd_buffer[8] = version_major + 0x30;
lcd_buffer[10] = version_minor + 0x30;
lcd_out(lcd_buffer);

Results in no real code bloat at all.

 

Online IanB

  • Super Contributor
  • ***
  • Posts: 11790
  • Country: us
Re: C function like printf but not sending to stdout? (XC8)
« Reply #28 on: March 12, 2013, 03:40:06 am »
Ooh, missed this one. Bad, very bad.

Yup, good catch.

The string "hello" is stored in memory as the byte sequence ('h', 'e', 'l', 'l', 'o', 0x00). The null byte is the end of string marker. String functions like lcd_out() or printf() look for this marker so they know when to stop. If you build your own character arrays you must make sure to put the null byte after the last position (many library routines like strcpy do this for you automatically, but watch out for the exceptions).
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: nz
Re: C function like printf but not sending to stdout? (XC8)
« Reply #29 on: March 12, 2013, 03:42:37 am »
If you're writing to a LCD panel it will be a fixed number of characters anyway.
So you could use a fixed length array of char.

Then you don't have to worry about lengths
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #30 on: March 12, 2013, 03:45:24 am »
Even more efficient:

Code: [Select]
lcd_outstr("Version ");
lcd_char(version_major + 0x30);
lcd_char('.');
lcd_char(version_minor + 0x30);
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #31 on: March 12, 2013, 03:47:46 am »
If you're writing to a LCD panel it will be a fixed number of characters anyway.
So you could use a fixed length array of char.

Then you don't have to worry about lengths

I have declared the lcd_buffer as:

Code: [Select]
unsigned char lcd_buffer[17];
As I assumed I needed the extra byte for the null terminator in addition to the actual 16 characters (max) for the display.
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: nz
Re: C function like printf but not sending to stdout? (XC8)
« Reply #32 on: March 12, 2013, 03:51:50 am »
yeah, if you want to manipulate it with the C string handling routenes you need the null on the end.
But you dont "have" to use those.

Since its just an array of numbers (like in delphi.. var lcd_buffer[16] : byte; ), you can do stuff to it directly as ascii numbers.
etc. you can copy or set the individual character positions, or the entire array using memcpy/memset and then you dont need the null and you don't get any overhead from the string funtions
« Last Edit: March 12, 2013, 03:58:21 am by Psi »
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #33 on: March 12, 2013, 03:53:38 am »
If I were using a character array to represent a "physical character array", I'd probably treat it like a true array rather than a string and skip the null. Can't really see why I would need to use string functions on something like that anyway.
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #34 on: March 12, 2013, 03:57:26 am »
My lcd output routine was adapted from something I found on the 'net:

Code: [Select]
void lcd_outstr(const char *buffer)
{
while(*buffer)              // Write data to LCD up to null
{
    lcd_char(*buffer); // Write character to LCD
    buffer++;               // Increment buffer
}
}

Does that make sense with the method of calling it?
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #35 on: March 12, 2013, 04:00:05 am »
Whenever I start learning a new programming language I usually write butt-ugly code to start with and improve (optimise) it with practice.

I'm not new to the concept of pointers, bytes, etc but was failing to recognise them in the C context.
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #36 on: March 12, 2013, 04:00:29 am »
Looks fine to me. And thank you thank you thank you for not using the old lcd_char(*buffer++) trick. (Hopefully I didn't give anyone any ideas...  :))

This might be a bit more conventional, though:
Code: [Select]
for ( ; *buffer; ++buffer) {
    lcd_char (*buffer);
}

(Yes, you can skip a section of the for-loop definitions. Just omit it and leave the semicolon.)
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: nz
Re: C function like printf but not sending to stdout? (XC8)
« Reply #37 on: March 12, 2013, 04:04:51 am »
Personally, i would forget pointers until you become familiar with C coding in general.
They tend to complicate things and its real easy to make mistakes.

You can make any program you want without having to use them.
They just make some things faster and quicker to code, since you can pass the memory address instead of the actual data
« Last Edit: March 12, 2013, 04:07:32 am by Psi »
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #38 on: March 12, 2013, 04:07:05 am »
I think I'm on the right track now thanks to you guys.

One more question; If there is only one statement to execute in the for loop, are the braces around that statement still required?
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #39 on: March 12, 2013, 04:08:15 am »
Yeah, they do complicate things, but you can't really do much at all without them in C...

I think I'm on the right track now thanks to you guys.

One more question; If there is only one statement to execute in the for loop, are the braces around that statement still required?

Nope. I tend to use them because they save rearranging stuff if I need them later. Also, if your editor doesn't auto-indent, omitting them can be a recipe for disaster, but the ones I use all do.

The technical explanation is that the contents of the loop is just one statement and no braces, and the braces and their own contents count collectively as one statement. You can also use them on their own, but that's not very useful.
« Last Edit: March 12, 2013, 04:10:13 am by c4757p »
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: nz
Re: C function like printf but not sending to stdout? (XC8)
« Reply #40 on: March 12, 2013, 04:09:18 am »
I think I'm on the right track now thanks to you guys.

One more question; If there is only one statement to execute in the for loop, are the braces around that statement still required?

nope, you only need the braces for multiple statements.

for (i=0;i<=10;i++)  myfunction();
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #41 on: March 12, 2013, 04:10:20 am »
Cool.  I thought the same "block rules" applied to C as I use in Delphi, etc (and it seemed to work) but thought I'd ask to be sure.
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #42 on: March 12, 2013, 04:14:10 am »
Delphi is Pascal, right? I haven't touched Pascal in ages, but I remember finding it strikingly similar to C.
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: nz
Re: C function like printf but not sending to stdout? (XC8)
« Reply #43 on: March 12, 2013, 04:16:36 am »
On the subject of braces(blocks)

Sometimes you may need to use them inside a case statement.

You can't declare a new variable inside a case statement unless its inside a block.

Code: [Select]
Switch (foo)
{
  case 1:
       char mychar;    <- doesnt work (you can't declare a new variable)
       mychar=5;
  break;
  case 2:
  {
       char mychar2;   <- works fine
       mychar2 = 10;
       break;
  }
}
However, since your used to Delphi (like me) its unlikely you'll ever want to declare variables in the middle of code.
It can be useful though, your case statement might be based on the mode your device is in. Some modes might need lots of math done and require many variables be declared which are not needed in other modes.
« Last Edit: March 12, 2013, 04:21:35 am by Psi »
Greek letter 'Psi' (not Pounds per Square Inch)
 

Online IanB

  • Super Contributor
  • ***
  • Posts: 11790
  • Country: us
Re: C function like printf but not sending to stdout? (XC8)
« Reply #44 on: March 12, 2013, 04:16:42 am »
This might be a bit more conventional, though:
Code: [Select]
for ( ; *buffer; ++buffer) {
    lcd_char (*buffer);
}

Danger, Will Robinson! This code explicitly assumes that the array of characters in buffer is null terminated. Given earlier comments about the possible omission of the terminator when using 16 byte fixed length arrays, this code snippet could lead to disaster...
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #45 on: March 12, 2013, 04:23:46 am »
This might be a bit more conventional, though:
Code: [Select]
for ( ; *buffer; ++buffer) {
    lcd_char (*buffer);
}

Danger, Will Robinson! This code explicitly assumes that the array of characters in buffer is null terminated. Given earlier comments about the possible omission of the terminator when using 16 byte fixed length arrays, this code snippet could lead to disaster...

Been thinking of including a max length check into the loop, but still pondering how.
 

Online IanB

  • Super Contributor
  • ***
  • Posts: 11790
  • Country: us
Re: C function like printf but not sending to stdout? (XC8)
« Reply #46 on: March 12, 2013, 04:47:36 am »
Been thinking of including a max length check into the loop, but still pondering how.

That's easy. Something like this:

Code: [Select]
#define LCD_BUFFER_SIZE 16

void lcd_outstr(const char *buffer)
{
    const char *end = buffer + LCD_BUFFER_SIZE;

    for ( ; buffer < end && *buffer; ++buffer) {
        lcd_char (*buffer);
}
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #47 on: March 12, 2013, 04:51:23 am »
Ah, you beat me to it.  I almost had it working but was looking up the AND operator.  ;D
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #48 on: March 12, 2013, 05:14:56 am »
Danger, Will Robinson! This code explicitly assumes that the array of characters in buffer is null terminated. Given earlier comments about the possible omission of the terminator when using 16 byte fixed length arrays, this code snippet could lead to disaster...

True, I was just working with what he already had. If I were treating it like an array I would use a normal length-bounded array iteration. Didn't notice the inconsistency.
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: C function like printf but not sending to stdout? (XC8)
« Reply #49 on: March 12, 2013, 06:19:23 am »
I need to somehow replicate the behaviour of printf in my function, but how?

Code: [Select]
#include <stdarg.h>
#include <stdio.h>

// returns number of characters printed
int lcd_printf(const char *format, ...) {
  va_list args;
  int count;
  char buffer[100]; // pick a reasonable size

  va_start(args, format);
  count = vsnprintf(buffer, sizeof(buffer), format, args);
  va_end(args);

  const char *p = buffer;
  while (*p) lcd_char(*p++);

  return count;
}

PS. Not guaranteed to work on rinky-dink development systems. ;-)
PPS. Does your lcd_char() handle CR and LF correctly?
« Last Edit: March 12, 2013, 06:21:20 am by andyturk »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf