View previous topic :: View next topic |
Author |
Message |
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
PCM's strlenc vs. CCS's strchr |
Posted: Tue Oct 02, 2007 8:18 pm |
|
|
I found PCM's GPS (thread dated 2003) code and he uses a unique function strlenc to locate a character within a string.
http://www.ccsinfo.com/forum/viewtopic.php?t=4402&highlight=strlenc
1. I couldn't find any other reference to the strlenc function on CCS.
2. I found offhand references on Google, but nothing really to compare.
3. I'm assuming that he used a hand rolled function because CCS hadn't provided the strchr function yet. AND, I can replace strlenc with strchr?
I looked in string.h and it looks as though strchr would do what PCM had intended with strlenc.
Thanks,
John
BTW, Thank-you PCM Programmer for the code. It looks like it will save A LOT of time and is much more elegant than I could ever hope for in my own spaghetti.... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Oct 02, 2007 8:44 pm |
|
|
strchr() scans a string for the first occurrence of a specified character
and returns a pointer to it. It returns NULL if the character is not found.
It's a standard C function.
strlenc() is, I believe, a custom function. It does something different.
It finds the length of the string before the occurrence of a character.
It doesn't return a pointer.
Code: |
// Find the length of string, up to, but not including
// the char c. Ie., if the char is at the start of the string,
// 0 is returned. If the char is the 2nd char in the string,
// 1 is returned, etc. Return 0xff if the char is not found.
char strlenc(char *strptr, char c)
{
char count = 0;
char temp;
while(1)
{
temp = *strptr++;
if(temp == 0) // Quit if end of string is found
{
count = 0xff; // Return 0xff to show that c was not found
break;
}
if(temp == c)
break;
count++;
}
return(count);
} |
|
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Tue Oct 02, 2007 9:08 pm |
|
|
Thank-you. Now that you explain that, I see that. I was also looking in the string.h file and seeing that many of the functions return a pointer (I assume that is the * prior to the function name?
It also looks like I'm going to have to change a lot of your code because of a different format of sentence... all the commas are there even if the data field is empty. But it will be a good exercise and you've given a good starting point.
I see that you use strchr16 which I assume is the same as strchr... except I'm not sure why the 16 is on the function name. Maybe a special function for LONG strings? But that doesn't make sense....
Thanks,
John |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Oct 02, 2007 9:17 pm |
|
|
That was a bug fix, for the vs. 2.xxx compiler. strchr() works OK
in the current compiler. |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Tue Oct 02, 2007 9:20 pm |
|
|
Thanks for the explanation.
I'm writing my own strccnt based on how you did the strlenc. After that I should be able to finish it up.
Thanks again,
John |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Oct 02, 2007 9:32 pm |
|
|
Just in case:
Code: |
// Count the number of occurrences of the specified character
// in a string.
char strccnt(char *strptr, char c)
{
char count = 0;
char temp;
while(1)
{
temp = *strptr++;
if(temp == 0) // Quit when end of string is found
break;
if(temp == c)
count++;
}
return(count);
} |
|
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Tue Oct 02, 2007 9:35 pm |
|
|
Here are the two approaches I came up with. I'd love to hear the pros and cons of each of these from a pro and how they relate to yours.
Code: | // Find the number of characters 'c' in the target string
char strccnt(char *strptr, char c)
{
char count = 0;
char temp;
temp = *strptr; // get the first character of the string
while(temp != 0x00) // continue to the null terminator
{
if(temp == c) // if the character is equal to search character
count++; // increment the character counter
temp = *strptr++; // move to next charcter in the string
}
return(count);
}
// Find the number of characters 'c' in the target string
char strccntXX(char *strptr, char c)
{
char count = 0;
char temp;
while(*strptr != 0x00) // continue to the null terminator
{
if(*strptr == c) // if the character is equal to search character
count++; // increment the character counter
*strptr++; // move to next charcter in the string
}
return(count);
} |
BTW, Thanks for the spoon feeding. It's always appreciated.... even more the later it gets. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Oct 02, 2007 10:13 pm |
|
|
Assuming that they work, you can just look at the .LST file and see
which routines are more efficient. I don't really spend a lot of time
trying improve little routines like this. They're only called a few times
and speed is not usually important. If it works, then it's good enough. |
|
|
inservi
Joined: 13 May 2007 Posts: 128
|
|
Posted: Wed Oct 03, 2007 2:15 am |
|
|
Hello jecottrell,
I think that in your first routine, you test the first char two time because you post increment *strptr ?
in the second routine, you declaring temp for nothing ?
Best regards,
dro. _________________ in médio virtus |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Wed Oct 03, 2007 8:48 am |
|
|
Ahhhh..... Thank-you. I looked up the pre and post increment in a shallow book and carried on. After your comments, I went to my O'reilly 'Practical C' and read in depth. It did a lot better at explaining when things happen.
Here is corrected code:
Code: | // Find the number of characters 'c' in the target string
char strccnt(char *strptr, char c)
{
char count = 0;
char temp;
temp = *strptr; // get the first character of the string
while(temp != 0x00) // continue to the null terminator
{
if(temp == c) // if the character is equal to search character
count++; // increment the character counter
temp = *strptr + 1; // move to next charcter in the string
}
return(count);
}
// Find the number of characters 'c' in the target string
char strccntXX(char *strptr, char c)
{
char count = 0;
//char temp; leftover from modifying previous function (delete)
while(*strptr != 0x00) // continue to the null terminator
{
if(*strptr == c) // if the character is equal to search character
count++; // increment the character counter
*strptr++; // move to next charcter in the string
}
return(count);
} |
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Oct 03, 2007 8:51 am |
|
|
Like PCM said, this function is so small, it is not worth the effort optimizing.
That said, there is a general design issue with the PIC processors that not everybody is aware of: pointers are not efficiently handled by the processor. To get the value of a pointer on a PIC18 the processor has to load the indirect addressing register FSR and then retrieve the value, a total of 10 clock cycles, even more on a PIC16. This is the reason for PCM introducing the temp variable, it saves a pointer access.
I like to demonstrate an efficient concept for when you have to walk a buffer like in the above functions. Using the FSRx registers in combination with the POSTINC or POSTDEC registers the address pointer will be incremented or decremented by the hardware saving two valuable clock cycles. Another large saving is that the pointer is only initialized once. The resulting function is about 26 bytes smaller than the alternatives from earlier in this thread.
Code: | // #word FSR0 = GETENV("SFR:FSR0L") // #word is in the Aug-2007 manual but not yet supported in my v4.038
int16 FSR0;
#locate FSR0 = GETENV("SFR:FSR0L")
#byte INDF0 = GETENV("SFR:INDF0")
#byte POSTINC0 = GETENV("SFR:POSTINC0")
// Find the number of characters 'SearchChar' in the target string.
char strccnt_FSR(char *StrPtr, char SearchChar)
{
char Count = 0;
FSR0 = StrPtr; // load pointer register FSR0 with start address of string.
while (INDF0) // equal to (*StrPtr) but more efficient.
{
if (POSTINC0 == SearchChar) // POSTINC0 is equal to (*StrPtr++)
Count++;
}
return Count;
} | This concept is also efficient when you have to work with two different pointers because the PIC has a total set of three addressing registers (FSR0, FSR1, FSR2).
Edit 1: I found out why #word is failing, it is a new directive not supported in my v4.038
Last edited by ckielstra on Wed Oct 03, 2007 9:30 am; edited 1 time in total |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Wed Oct 03, 2007 8:58 am |
|
|
Thank-you for the explanation.
That sheds light on why PCM also used a similar approach in the GPS code that this all relates to. I was just assuming the more complex the code, the more efficient it would be..... (great assumption, huh?)
A generalization would be: If you are going to refer back to the value of a pointer numerous times, put it in a variable.... then refer back to the variable?
John |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Oct 03, 2007 9:24 am |
|
|
jecottrell wrote: | A generalization would be: If you are going to refer back to the value of a pointer numerous times, put it in a variable.... then refer back to the variable? | Yes, that pretty much sums it up. |
|
|
|