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

0 Members and 1 Guest are viewing this topic.

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
C function like printf but not sending to stdout? (XC8)
« on: March 12, 2013, 01:21:50 am »
Being new to C programming, I just can't seem to figure this one out.

I am sending a string my LCD write function.  The function works fine with variable length text as I use a buffer.

Code: [Select]
void lcd_out(const char *buffer);
Now, how do I send it a formatted string like so?

Code: [Select]
lcd_out("Version %d.%d", verMajor, verMinor);
I need to somehow replicate the behaviour of printf in my function, but how?
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: nz
Re: C function like printf but not sending to stdout? (XC8)
« Reply #1 on: March 12, 2013, 01:25:51 am »
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 #2 on: March 12, 2013, 01:25:57 am »
sprintf will format a string into a buffer. Be very careful of buffer overflow - snprintf prevents this, but is not present in all C libraries.
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 #3 on: March 12, 2013, 01:54:40 am »
Hmmm... seems I really don't understand how strings and pointers work in C.  I usually program in Delphi and other languages - anything other than C !

How do I:
  • Declare a string (for the LCD buffer)
  • Assign text to that string
  • Pass that to my LCD function
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #4 on: March 12, 2013, 01:57:54 am »
That's because C doesn't have strings. It just has character arrays, and a string literal is just shorthand for a predefined character array. You need to declare a character array "char my_array[length];", you can set its value with strcpy (watch the length!), and you can just pass it by name.
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 #5 on: March 12, 2013, 02:15:52 am »
Gotcha.  OK, I now have this working:

Code: [Select]
lcd_set_cursor(1,0);
strcpy(lcd_buffer,"My Project");
lcd_out(lcd_buffer);
lcd_set_cursor(2,0);
sprintf(lcd_buffer,"Version %d.%d",version_major,version_minor);
lcd_out(lcd_buffer);

Thanks for your help guys.  Learning a new language can be frustrating at times, but I think I learned a reasonable amount from that.   :)
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #6 on: March 12, 2013, 02:25:41 am »
If you're just printing a constant string, you don't need

Code: [Select]
strcpy(lcd_buffer,"My Project");
lcd_out(lcd_buffer);

You can just use lcd_out("My Project");. Use strcpy if you need to start filling a buffer (then you can use strcat to append).
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline Harvs

  • Super Contributor
  • ***
  • Posts: 1202
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #7 on: March 12, 2013, 02:36:17 am »
Keep in mind that the use of some of these type of standard library functions (like printf, sprintf etc.) can be far too heavy for a memory limited uC, so you need to watch your compiled code size.  Possibly the one included with XC8 has been optimized for use in a uC, but often you're better off rolling your own char array manipulation routines for the specific application.  E.g. if you're always just converting an unsigned int to decimal and inserting it at a particular location you can do that with very little memory or processor time.
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #8 on: March 12, 2013, 02:53:34 am »
If you're just printing a constant string, you don't need

Code: [Select]
strcpy(lcd_buffer,"My Project");
lcd_out(lcd_buffer);

You can just use lcd_out("My Project");. Use strcpy if you need to start filling a buffer (then you can use strcat to append).

I tried that but get an error:

Code: [Select]
illegal conversion between pointer types
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #9 on: March 12, 2013, 02:55:18 am »
It's been a while, so this is a shot in the dark, but change your lcd_out definition from taking a char * to a char const *.
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 #10 on: March 12, 2013, 02:59:01 am »
Perfect!  Thanks very much for that.   :)
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1310
  • Country: 00
Re: C function like printf but not sending to stdout? (XC8)
« Reply #11 on: March 12, 2013, 03:00:59 am »
Like Harvs says, the sprintf() library code is going to be pretty chunky due to the fact that it has to support a ton of different formatting options.  In the case of your example it would be more efficient to use the itoa() function to get the integer variables into string format.  If your compiler supports itoa(), that is.  It isn't part of the standard but most compilers support it.

Code: [Select]
.
.
.
lcd_set_cursor(2,0);
lcd_out("Version ");
lcd_out(itoa(version_major, version_buffer, 10)); // 10 == numerical base.
lcd_out(".");
lcd_out(itoa(version_minor, version_buffer, 10));

Just something to keep in mind in case you start running out of program space.
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #12 on: March 12, 2013, 03:02:22 am »
When you give a string in quotes, the compiler is free to store it wherever it wants, including in read-only memory, so it will refuse to pass it to a function that can modify it. "char const *" means "pointer to a constant (read-only) character". Some compilers do not enforce this, which is why it didn't occur to me at first.
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #13 on: March 12, 2013, 03:03:19 am »
In the case of your example it would be more efficient to use the itoa() function to get the integer variables into string format.  If your compiler supports itoa(), that is.  It isn't part of the standard but most compilers support it.

Good point.
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 #14 on: March 12, 2013, 03:15:38 am »
Interesting.  The sprintf version adds 569 words of code, while the itoa version only adds 287 words.  Still bloated compared to the assembler I'm used to writing.

On a related point, with assembler I used to convert a simple 0..9 integer to an ASCII character (for display) by adding 0x30 to it.  I assume that sort of thing is also possible in C?
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #15 on: March 12, 2013, 03:17:41 am »
Absolutely. In fact, a char isn't even really a character, it's just an 8-bit integer. You can do math on them directly.
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline Rufus

  • Super Contributor
  • ***
  • Posts: 2095
Re: C function like printf but not sending to stdout? (XC8)
« Reply #16 on: March 12, 2013, 03:17:57 am »
Possibly the one included with XC8 has been optimized for use in a uC,

One of the features of the (ex) Hi-Tech compilers is 'omniscient code generation' which effectively compiles the entire program and used libraries as a single module. That gives the optimiser visibility of the entire program allowing it to remove redundant code. I suspect they jump through additional hoops with the printf series parsing possible format strings to know what is redundant.

With the free version you only get messages telling you how much better the paid for one would be. Some claim the free version deliberately generates horrid code, personally I think it is just an indication of how much work the optimiser is expected to do.
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: nz
Re: C function like printf but not sending to stdout? (XC8)
« Reply #17 on: March 12, 2013, 03:19:04 am »
On a related point, with assembler I used to convert a simple 0..9 integer to an ASCII character (for display) by adding 0x30 to it.  I assume that sort of thing is also possible in C?

yep, that still works fine.
As said above, a char is just an 8 bit number. So you can do maths on them however you want.
« Last Edit: March 12, 2013, 03:21:43 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 #18 on: March 12, 2013, 03:22:22 am »
People keep telling me how C code is so much quicker to write than assembler, but I'm old (actually middle age!) and have been somewhat set in my ways.

I'm sure I'll get better at writing C code, but it's painfully slow at present.

I've been pondering whether the standard or pro version of XC8 would be the way to go.  Code space it probably not so much of an issue, but some projects I do use DMX and some high speed SPI data streaming so speed of execution can be important.
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: C function like printf but not sending to stdout? (XC8)
« Reply #19 on: March 12, 2013, 03:25:49 am »
People keep telling me how C code is so much quicker to write than assembler, but I'm old (actually middle age!) and have been somewhat set in my ways.

I can bang out PIC assembly pretty fast. I rarely revert to C on an 8-bit micro, though I do use it for the 16- and 32-bit ones.
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 11790
  • Country: us
Re: C function like printf but not sending to stdout? (XC8)
« Reply #20 on: March 12, 2013, 03:26:59 am »
Interesting.  The sprintf version adds 569 words of code, while the itoa version only adds 287 words.  Still bloated compared to the assembler I'm used to writing.

On a related point, with assembler I used to convert a simple 0..9 integer to an ASCII character (for display) by adding 0x30 to it.  I assume that sort of thing is also possible in C?

Sure. Something like this:

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

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

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

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #21 on: March 12, 2013, 03:29:22 am »
This works:

Code: [Select]
char temp;
temp = version_major+0x30;
lcd_out(&temp);

But this doesn't:

Code: [Select]
lcd_out(version_major+0x30);
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: C function like printf but not sending to stdout? (XC8)
« Reply #22 on: March 12, 2013, 03:30:53 am »
Interesting.  The sprintf version adds 569 words of code, while the itoa version only adds 287 words.  Still bloated compared to the assembler I'm used to writing.

On a related point, with assembler I used to convert a simple 0..9 integer to an ASCII character (for display) by adding 0x30 to it.  I assume that sort of thing is also possible in C?

Sure. Something like this:

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

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

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

Ooh... I like that.  Using the array as ... well an array!
 

Offline c4757p

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

(As an aside, it's also "portable", as in "back when C was designed not everything was ASCII", but that's kind of like buying a trailer for your pickup truck that is also horse-compatible...)

This works:

Code: [Select]
char temp;
temp = version_major+0x30;
lcd_out(&temp);

But this doesn't:

Code: [Select]
lcd_out(version_major+0x30);

Like I said, a char is just a number. You've got to put it in a string/array. If you're doing it a lot of times and can spare the space for code, it may be more efficient to make a second function that just takes a single char.
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 11790
  • Country: us
Re: C function like printf but not sending to stdout? (XC8)
« Reply #24 on: March 12, 2013, 03:32:09 am »
But this doesn't:

Code: [Select]
lcd_out(version_major+0x30);

No; the lcd_out function is expecting the address of a character array in memory. The expression (version_major+0x30) is not a memory address it is an immediate value. Note that whenever you pass a string like "foo" into a function you are really passing the memory address of the first character 'f'.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf