I am porting some code to an 8051. (header.h)
typedef int (Writer) (int , u_char * , u_char , size_t , u_char * , int *) reentrant;
Writer bob;
. . . int bob(int val1, u_char * dat1, u_char dat2, size_t val2, u_char * dat3, int *pval) reentrant { }
//Comment out Writer bob; int (bob)(int val1, u_char * dat1, u_char dat2, size_t val2, u_char * dat3, int *pval) reentrant;
The problem is not really the typedef itself --- which is a function type, rather than the function pointer type your subject alludes to. The problem is how you use it.
extern Writer bob;
The .h file provides a "prototype" of a function to be defined elsewhere. The redefinition warning means that when you actually define the function in the .c file, it does not match a previously seen declaration (typically in a .h file). While you've run into this problem with the reentrant attribute, it applies to any change in function signature. That is, .h: void MyFunction (long a); .c: void MyFunction (short a); would produce a redefinition warning. The .h file should always match the actual definition of the function, lest you confuse seperately-compiled callers.
The .h file provides a "prototype" of a function to be defined elsewhere. That what it should do, for ordinary functions. But the case at hand is different, because
"the proper way of making sure of this is to always include the module's header file into its own .c file." Yep - that's what I always say!
Thank you for the help. Extern did not improve anything unforunately. It appears that it is coded this way because the function is also passed within structures and other functions. In this way, we are not rewriting all of the details of the function pointer. This style is being used quite often in the code. I only seem to have a problem when I am forced to define the function as reentrant(too many arguments). For example:
(header.h) typedef int (Writer) (int); Writer bob;
(header.c) int bob(int a){ ... }
"I am only having the problem when the function is too large and I have to redefine it as reentrant." Why does the Size of the function affect the need for the reentrant attribute?
"I am porting some code to an 8051.typedef int (Writer) (int , u_char * , u_char , size_t , u_char * , int *) reentrant; Now would be a good time to do away with using int, then. I would also prefer to use a more explicit name that "u_char" - my preferred names are U8, U16, U32, etc for Unsigned 8-bit, 16-bit, 32-bit, etc; S8, S16, S32, etc for Signed 8-bit, 16-bit, 32-bit, etc. These are explicit, concise & precise!
Check out: http://www.keil.com/support/docs/2066.htm An excerpt.... When parameters passed to a function via a function pointer will not fit into registers, the compiler cannot determine where in memory to place the parameters since the function is not known at call-time...... Solution #1 Create reentrant functions using the reentrant function attribute. The compiler simulates a stack-based architecture which makes it possible to pass a virtually unlimited number of parameters to indirectly called functions. The other solution is to change functions parameters so that they fit into CPU registers. I may eventually do this, but right now I am creating a prototype and I just need the code to work.
I see - not the size of the function, but the size of its parameters! Note that this gives you a major performance hit!
Thanks for the info. I'll probably have to deal with performance once I get it running and that may mean a rewrite. Any ideas on how I can add the reentrant attribute and still use the function data type ? (e.g. ..
typedef int Writer(int, u_char *, void * void *) reentrant;
I still suspect that the root of your problem is the whole idea of a "function data type". In your own subject line and some of your posts, you mention function pointers, but there's not a single function pointer anywhere in sight. A typedef for a function object type is almost certainly the wrong solution for whatever the problem is you're trying to solve. If you want a typedef for a function pointer --- fine, make one. But don't confuse it with a function type. The symptoms seem to suggest that Keil doesn't store "reentrant" as part of the function type info. You may have to write
Writer bob reentrant;
Do you already have this code running on some other platform? If so, might it not be easier to re-engineer it on that platform to do away with the need for these problematic (for C51) function pointers, and then port the resulting C51-friendly code to the 8051? Or is this some so-called "portable" reference code that you're trying to get onto C51? Again, might it be easier to start by implementing it on a more conventional, C-friendly, target (eg, a PC) first, and then proceed as above? Just a thought - it's worked for me before.
Hans-Bernhard, Yes, I made a mistake in calling this a function pointer type instead of a function type. The function type seems like the best approach since the function type is being passed in many functions and structures and it wouldn't make sense to redefine the entire function each time. Thank you for the suggestions and comments. I have tried to do the following:
Write bob reentrant;
This is code that runs on windows, but was written in a portable manner. I am using the windows version quite a bit for reference. I could go back to windows, but the problem is that I will inevitably have to deal with the C51 issues and I have so far opted to face them head on. (my head hurts!) It hasn't been bad so far except for the reentrant attribute. Thanks for the suggestions.......
"This is code that runs on windows, but was written in a portable manner." Trouble is, C51 is an unconventional implementation of 'C' - particularly the way that it does not use the hardware stack for function parameters & locals. Conventional 'C' functions are inherently reentrant; C51 functions are inherently non-reentrant. Therefore, even the best-designed "portable" 'C' that relies on reentrant functions (as found in 99% of 'C' implementations) will break on C51. :-( "I could go back to windows, but the problem is that I will inevitably have to deal with the C51 issues" Absolutely - but couldn't that be biting off too much at once? I'm just suggesting that you take it a step at a time: First, stick with the familiar, conventional Windows environment and remove the reentrancy requirement; Then, when you know you've got it working non-reentrant, move it to C51 and address all the other issues (word size, byte ordering, etc, etc)