Author Topic: Pic XC8: ftoa() another dummy question.  (Read 9262 times)

0 Members and 1 Guest are viewing this topic.

Offline DTJTopic starter

  • Frequent Contributor
  • **
  • Posts: 997
  • Country: au
Pic XC8: ftoa() another dummy question.
« on: January 03, 2017, 09:53:05 am »
I'm a novice trying to convert a float variable to an ascii string and it's not going too well.

I'm using MPLABx + XC8 lite + P18LF14k22


I've got a temperature value as a float that I want to convert to an ASCII string.

Attached below is a grab of the output from the code I'm trying out.


The conversion is only doing the first character. In the example its the '-' sign.
I'm sure this is because I'm not specifying the length of the output char array.

However if I try to declare the array with say 8 elements as below:

unsigned char buf[8];   //temp ascii string

........the compiler balks at the ftoa() line.


How should I be implementing this?  :-//
Thanks



My code:

Code: [Select]

char * buf;                                                       // <<<< I don't think this is declared correctly
float input = -14.25685;  //test value 1
//float input = 52.54821;  //test value 2
int status;

buf = ftoa(input, &status);





This is from the XC8 Compiler User Manual:

Quote
FTOA
Synopsis
#include <stdlib.h>
char * ftoa (float f, int * status)


Description

The function ftoa converts the contents of f into a string which is stored into a buffer
which is then return.


Example:

#include <stdlib.h>
#include <stdio.h>
void
main (void)
{
 char * buf;
 float input = 12.34;
 int status;
 buf = ftoa(input, &status);
 printf("The buffer holds %s\n", buf);
}
« Last Edit: January 03, 2017, 10:54:56 am by DTJ »
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1714
  • Country: se
Re: Pic XC8: ftoa() another dummy question.
« Reply #1 on: January 03, 2017, 10:25:56 am »
Given the (very incomplete: what is status, how long is the buffer, etc...) description of the ftoa() function, your code is correct.

The return value is the address of the buffer (which is probably statically allocated).

The compiler is right in rejecting the assignment to buf, when declared as an array: in C, array variables cannot be used as lvalues (in simple words: as targets of an assignment).

You are seeing just the first character of the converted number ('-') because buf is a char pointer, and the IDE/debugger gives you...just the char pointed to!
Try examining the memory at the address pointed by buf, or actually print it out using printf()/puts(), and I'm quite sure your ASCII representation of the floating point number will be there.
« Last Edit: January 03, 2017, 10:36:20 am by newbrain »
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26751
  • Country: nl
    • NCT Developments
Re: Pic XC8: ftoa() another dummy question.
« Reply #2 on: January 03, 2017, 10:37:28 am »
declare buf as:
char buf[20]
where 20 must be big enough to contain all characters and a terminating zero (google C strings).
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline matseng

  • Frequent Contributor
  • **
  • Posts: 563
  • Country: se
    • My Github
Re: Pic XC8: ftoa() another dummy question.
« Reply #3 on: January 03, 2017, 10:38:50 am »
Looks fine to me. The ftoa returns a pointer to a char, so the "char *buf" declaration is ok.

Since the returned value really is a pointer to an array of chars you have to iterate over the characters until you encounter a 0-value.
Code: [Select]
char ch;
char *p; // make a copy of the buf pointer
p=buf;
while (*p!=0) { // not reached the end?
  ch=*p; // fetch next character
  /* do something with ch here */
   p=p+1; // jump to next character
}
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1714
  • Country: se
Re: Pic XC8: ftoa() another dummy question.
« Reply #4 on: January 03, 2017, 10:42:20 am »
declare buf as:
char buf[20]
where 20 must be big enough to contain all characters and a terminating zero (google C strings).
Not with ftoa() declared as it is, unless he strcpy the returned buffer into buf.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline DTJTopic starter

  • Frequent Contributor
  • **
  • Posts: 997
  • Country: au
Re: Pic XC8: ftoa() another dummy question.
« Reply #5 on: January 03, 2017, 10:54:22 am »
declare buf as:
char buf[20]
where 20 must be big enough to contain all characters and a terminating zero (google C strings).

ntnico - thanks - I tried that and it wont compile - fails at the ltoa()



You are seeing just the first character of the converted number ('-') because buf is a char pointer, and the IDE/debugger gives you...just the char pointed to!
Try examining the memory at the address pointed by buf, or actually print it out using printf()/puts(), and I'm quite sure your ASCII representation of the floating point number will be there.


newbrain - Yes - on your suggestion I checked the data memory and I can see the correct values in there. See attached screen grab.



Looks fine to me. The ftoa returns a pointer to a char, so the "char *buf" declaration is ok.

Since the returned value really is a pointer to an array of chars you have to iterate over the characters until you encounter a 0-value.
Code: [Select]
char ch;
char *p; // make a copy of the buf pointer
p=buf;
while (*p!=0) { // not reached the end?
  ch=*p; // fetch next character
  /* do something with ch here */
   p=p+1; // jump to next character
}



matseng - ok so I think I'm almost understanding what is happening. The output array is dynamically created and I either need to use it directly (breaking out when the null 0x00 is reached) or to keep it simple for me to understand I need to read it into a buffer where I can see it & work forward from there?

Hmmmm. I spotted something interesting, there is a difference between the input test value and the output string in memory:
float input          = -14.25685;  //test value 1
data in memory = -14.256836





Many thanks for your suggestions guys. I'd be stuffed without your kind help.

I'll go and play around and see if I can get it working.  :-+
« Last Edit: January 03, 2017, 10:59:05 am by DTJ »
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1714
  • Country: se
Re: Pic XC8: ftoa() another dummy question.
« Reply #6 on: January 03, 2017, 11:02:58 am »
matseng - ok so I think I'm almost understanding what is happening. The output array is dynamically created and I either need to use it directly (breaking out when the null 0x00 is reached) or to keep it simple for me to understand I need to read it into a buffer where I can see it & work forward from there?


Many thanks for your suggestions guys. I'd be stuffed without your kind help.

I'll go and play around and see if I can get it working.  :-+
Unless you can see the ftoa() source it's difficult to say whether the ftoa() buffer is statically or dynamically allocated.
I suspect it's static, with a reasonable size, and hence overwritten every time you call ftoa().

This is easy to check: does ftoa() return always the same vale for buf (i.e. the memory address you examined) on subsequent calls?
Yes: static allocation
No: dynamic allocation (but this would be a memory leak, as no instructions are given to release the buffer).

In the first case, you might need to copy/process it before calling ftoa() again.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline DTJTopic starter

  • Frequent Contributor
  • **
  • Posts: 997
  • Country: au
Re: Pic XC8: ftoa() another dummy question.
« Reply #7 on: January 03, 2017, 11:16:25 am »
matseng - ok so I think I'm almost understanding what is happening. The output array is dynamically created and I either need to use it directly (breaking out when the null 0x00 is reached) or to keep it simple for me to understand I need to read it into a buffer where I can see it & work forward from there?


Many thanks for your suggestions guys. I'd be stuffed without your kind help.

I'll go and play around and see if I can get it working.  :-+
Unless you can see the ftoa() source it's difficult to say whether the ftoa() buffer is statically or dynamically allocated.
I suspect it's static, with a reasonable size, and hence overwritten every time you call ftoa().

This is easy to check: does ftoa() return always the same vale for buf (i.e. the memory address you examined) on subsequent calls?
Yes: static allocation
No: dynamic allocation (but this would be a memory leak, as no instructions are given to release the buffer).

In the first case, you might need to copy/process it before calling ftoa() again.


Thanks newbrain.
I'll run it  a few times and see if it stays in the same location.

I copied the array as suggested and it seems to work well with the converted value saved in the TempStr[] array.
My code is below - it needs a clean up.


Many thanks!


Code: [Select]
// convert float Temp_C to an ASCII string in unsigned char TempStr[]
Temp_C = -14.25685;  //test value 1
Temp_C = 52.54821;  //test value 2
char TempStr[8]; //temperature ascii string


char * buf;
// char buf[20]
float input = -14.25685;  //test value 1
//float input = 52.54821;  //test value 2
int status;
int gCount = 0;

buf = ftoa(input, &status); // output string is not in this dynamically created buffer.
// data can be used directly from there or copied to another static buffer.

//copy to a static buffer
char ch;
char *p; // make a copy of the buf pointer
p=buf;
gCount = 0;
while (*p!=0) { // not reached the end?
                ch=*p; // fetch next character
                TempStr[gCount] = *p;    //copy from buf to TempStr[]   
                p=p+1; // jump to next character
                gCount = gCount + 1;
              }

 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1714
  • Country: se
Re: Pic XC8: ftoa() another dummy question.
« Reply #8 on: January 03, 2017, 11:31:37 am »
My code is below - it needs a clean up.


Many thanks!


Code: [Select]
// convert float Temp_C to an ASCII string in unsigned char TempStr[]
Temp_C = -14.25685;  //test value 1
Temp_C = 52.54821;  //test value 2
char TempStr[8]; //temperature ascii string


char * buf;
// char buf[20]
float input = -14.25685;  //test value 1
//float input = 52.54821;  //test value 2
int status;
int gCount = 0;

buf = ftoa(input, &status); // output string is not in this dynamically created buffer.
// data can be used directly from there or copied to another static buffer.

//copy to a static buffer
char ch;
char *p; // make a copy of the buf pointer
p=buf;
gCount = 0;
while (*p!=0) { // not reached the end?
                ch=*p; // fetch next character
                TempStr[gCount] = *p;    //copy from buf to TempStr[]   
                p=p+1; // jump to next character
                gCount = gCount + 1;
              }

You're welcome!

And yes, your code needs some improvements, which I'll leave to you to implement.
  • The TmpStr array is of insufficient size: even looking at your memory dump, you can see that more than 8 characters are needed, and don't forget the terminating 0. Nctnico suggestion of 20 chars should be enough.
  • The copy loop is not correct, you miss the terminating 0...
  • ...and it's definitely not "idiomatic" C (not a fault per se, but common idioms are easier to understand when reading someone else's code, and in this case the idiiomatic version would be shorter and without the off-by-one error!)


Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: DTJ

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12806
Re: Pic XC8: ftoa() another dummy question.
« Reply #9 on: January 03, 2017, 11:41:08 am »

Unless you can see the ftoa() source it's difficult to say whether the ftoa() buffer is statically or dynamically allocated.
I suspect it's static, with a reasonable size, and hence overwritten every time you call ftoa().
...
In the first case, you might need to copy/process it before calling ftoa() again.
Its static.  See sources\common\ftoa.c (from XC8 folder)
Code: [Select]
#include <stdlib.h>
#include <stdio.h>

// quick and dirty ftoa for legacy code
char *
ftoa(float f, int * status)
{
static char buf[17];
char * cp = buf;
unsigned long l, rem;

if(f < 0) {
*cp++ = '-';
f = -f;
}
l = (unsigned long)f;
f -= (float)l;
rem = (unsigned long)(f * 1e6);
sprintf(cp, "%lu.%6.6lu", l, rem);
return buf;
}
Its also fugly and calls sprintf(), so you might as well simply sprintf() to your own buffer or even implement putch() four output device and printf() directly to it!
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26751
  • Country: nl
    • NCT Developments
Re: Pic XC8: ftoa() another dummy question.
« Reply #10 on: January 03, 2017, 12:17:39 pm »
declare buf as:
char buf[20]
where 20 must be big enough to contain all characters and a terminating zero (google C strings).
Not with ftoa() declared as it is, unless he strcpy the returned buffer into buf.
Sigh... too much C++  :-[
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline DTJTopic starter

  • Frequent Contributor
  • **
  • Posts: 997
  • Country: au
Re: Pic XC8: ftoa() another dummy question.
« Reply #11 on: January 06, 2017, 07:14:14 am »

You're welcome!

And yes, your code needs some improvements, which I'll leave to you to implement.
  • The TmpStr array is of insufficient size: even looking at your memory dump, you can see that more than 8 characters are needed, and don't forget the terminating 0. Nctnico suggestion of 20 chars should be enough.
  • The copy loop is not correct, you miss the terminating 0...
  • ...and it's definitely not "idiomatic" C (not a fault per se, but common idioms are easier to understand when reading someone else's code, and in this case the idiiomatic version would be shorter and without the off-by-one error!)

Thanks newbrain - I fixed the bugs you pointed out.

Thanks Ian - I'll think leave the sprintf() implementation until next year when I understand a little more! I'm just glad it seems to be working.

nctnico.  :-+
 

Offline ericmichael

  • Newbie
  • Posts: 1
  • Country: de
Re: Pic XC8: ftoa() another dummy question.
« Reply #12 on: January 10, 2017, 09:47:29 am »
Its also fugly and calls sprintf(), so you might as well simply sprintf() to your own buffer or even implement putch() four output device and printf() directly to it!

I you compare
Code: [Select]
char * buff;
float input = 12.34;
int status;
buff = ftoa(input, &status);

with

Code: [Select]
char buff[20];
float input = 12.34;
sprintf(buff,"%f",input);

the sprintf version uses 4554 more bytes of flash, than that used by the ftoa version.

Cheers,
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12806
Re: Pic XC8: ftoa() another dummy question.
« Reply #13 on: January 10, 2017, 10:18:43 am »
Yes. That's because you've just compiled in support for the '%f' format specifier which previously wasn't used  as the sprintf() in XC8 ftoa() uses the '%l' specifier.  It may be worth the extra FLASH, if the more flexible formatting helps you and if you have several floating point variables that need printing.

If you want to do much better you will need to search for an algorithm that can convert IEEE-754 32 bit binary floats (or Microchip's proprietary 24 bit modification of that format) direct to decimal ASCII.  Caution: many IEEE-754 ftoa() implementations need 64 bit integers which XC8 doesn't support.
« Last Edit: January 10, 2017, 10:28:52 am by Ian.M »
 

Offline Euphyllia

  • Newbie
  • Posts: 9
Re: Pic XC8: ftoa() another dummy question.
« Reply #14 on: January 14, 2017, 07:33:41 pm »
Is this a learning exercise or an actual project you're working on? With an 8-bit PIC the first problem with this code in the real world is the fact the word "float" appears anywhere ;) If it's just learning or practice then please ignore.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf