View previous topic :: View next topic |
Author |
Message |
kender
Joined: 09 Aug 2004 Posts: 768 Location: Silicon Valley
|
Problem between function pointers and [alleged] recursion. |
Posted: Wed Dec 25, 2013 8:51 pm |
|
|
Colleagues,
Here’s an example, where compiler suspects that the there may be recursion and generates an error “Recursion not permitted (function_name)”. But, the recursion doesn’t actually happen.
Arguments in this example only make function signatures distinct. They don’t serve any other purpose.
Code: | // Two different function pointers for completely different purposes. Same signatures, but function with different purposes and same signatures aren't uncommon.
int8 (*g_fpFoo)(int8 a);
int8 (*g_fpBar)(int8 a);
int8 one_more_down(); // function prototype
int8 foo1(int8 a)
{
return one_more_down();
}
int8 foo2(int8 a) { return 2; }
int8 bar1(int8 a) { return 11; }
int8 bar2(int8 a) { return 12; }
int8 one_more_down()
{
int8 iRet;
iRet = (*g_fpBar)(42);
return iRet;
}
void main()
{
int8 i, k,
iSomeCondition, iSomeOtherCondition;
switch(iSomeCondition) // initialize function pointer depending on some external condition
{
case 1: g_fpFoo = foo1; break;
case 2: g_fpFoo = foo2; break;
};
switch(iSomeOtherCondition) // initialize function pointer depending on some external condition
{
case 1: g_fpBar = bar1; break;
case 2: g_fpBar = bar2; break;
};
while (1)
{
i = (*g_fpFoo)(k); // make the call through the function pointer
}
}
|
This generates an error "Recursion not permitted [foo1]". There's no actual recursion in this code, as you can see. Also, there's plenty of stack left. I've been trying to find the source of the problem for hours. Finally, I've tweaked the code so that is compiles and looked at the call tree. Here it is.
Every function with matching signature is on the list, even though only bar1 and bar2 may get called. There’s no actual recursion. But, the compiler suspect that there may be recursion.
Are there workarounds for this?
Any suggestion, insight or reference is really appreciated!
Cheers,
- Nick
PIC18F4550
4.081 _________________ Read the label, before opening a can of worms. |
|
![](templates/subSilver/images/spacer.gif) |
stinky
Joined: 05 Mar 2012 Posts: 99 Location: Central Illinois
|
|
Posted: Thu Dec 26, 2013 12:07 am |
|
|
Function pointers are not flawless in CCS. Recursion is not permitted and a call to a function pointer is actually calling a built in function. If you attempt to call it again you are inviting recursion. |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1328
|
|
Posted: Thu Dec 26, 2013 9:52 am |
|
|
To addon to what was said, the PIC micros don't natively support function pointers well. CCS has to do some tricky stuff to make it work on the architecture at all. One of those is an internal function it calls. If memory serves me correct, it is something like @gotoptr. Calling a recursive function within a recursive function calls @gotoptr inside @gotoptr, which is recursion.
So while it appears your methods don't recurse, they actually do in order to make function pointers work. It's a limitation of the hardware moreso than the compiler. |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Dec 26, 2013 9:59 am |
|
|
The problem behind "recursion not allowed" is that CCS C allocates storage for local variables and function
arguments globally, analyzing the call tree to avoid memory conflicts.
Function pointers break the compiler's ability to determine the call hierarchy. As you probably already know,
giving a different function type to the second level functions by adding a dummy argument is a workaround for the
present example. |
|
![](templates/subSilver/images/spacer.gif) |
kender
Joined: 09 Aug 2004 Posts: 768 Location: Silicon Valley
|
|
Posted: Thu Dec 26, 2013 4:45 pm |
|
|
FvM wrote: | As you probably already know,
giving a different function type to the second level functions by adding a dummy argument is a workaround for the
present example. |
Yes, I have thought about dummy parameters too. But, I was hoping that there may be a less hacky way.
It seems that making a typedef is enough to make the signatures distinct. The following compiles without a recursion error.
Code: | typedef int8 fooParam;
int8 (*g_fpFoo)(fooParam a);
int8 (*g_fpBar)(int8 a);
int8 one_more_down(); // function prototype
int8 foo1(fooParam a)
{
return one_more_down();
}
int8 foo2(fooParam a) { return 2; }
// the rest of the example remains the same as in the O.P. |
_________________ Read the label, before opening a can of worms. |
|
![](templates/subSilver/images/spacer.gif) |
|