Technical Support
Support Resources
Product Information
|
C51: Passing Parameters to Indirectly Called Functions
Information in this article applies to:
- C51 All Versions
- Cx51 All Versions
SYMPTOMS
I'm using function pointers and object-oriented programming
techniques in my application. Most of the time my program works as
expected. But when I try to pass several parameters to functions that
are called via pointers, I get the following compiler error
message:
Error 212: Indirect call: Parameters do not fit within registers.
The program example below demonstrates this:
void (*CallBack1) (void *, unsigned char);
void (*CallBack2) (void *, void *);
void (*CallBack3) (char, char, char);
void (*CallBack4) (char, char, char, char);
unsigned char c, d, e, f;
char *ptr;
void test (void) {
CallBack1 (ptr, c); // works
CallBack2 (ptr, ptr); // fails - C51 generates an error message
// indirect call: parameters do not fit within
registers */
CallBack3 (c, d, e); // works
CallBack4 (c, d, e, f); // fails - C51 generates an error message
// indirect call: parameters do not fit within
registers */
}
CAUSE
Unlike most 16-bit and 32-bit microcontrollers, the 8051 is not a
stack based architecture. When parameters do not fit into the CPU
registers, the Keil Cx51 Compiler by default uses direct memory
locations for parameter passing. This technique generates very
efficient code but limits the parameters that can be passed to
indirectly called functions. 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.
RESOLUTION
There are two ways to solve your programming problem.
-
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. For example:
void (*CallBack1) (void *, unsigned char);
void (*CallBack2) (void *, void *) reentrant;
void (*CallBack3) (char, char, char);
void (*CallBack4) (char, char, char, char) reentrant;
unsigned char c, d, e, f;
char *ptr;
void test (void) {
CallBack1 (ptr, c); // works
CallBack2 (ptr, ptr); // works, but now the function that gets called
// need to have the reentrant attribute
CallBack3 (c, d, e); // works
CallBack4 (c, d, e, f); // works, but now the function that gets called
// need to have the reentrant attribute
}
-
Limit the number and types of parameters so that they all fit
into CPU registers. Do this when you need utmost performance or
when program size is critical. For example:
void (*CallBack1) (void *, unsigned char);
void (*CallBack2) (void xdata *, void xdata *);
void (*CallBack3) (char, char, char);
void (*CallBack4) (char, char, int);
unsigned char c, d, e, f;
char xdata *ptr;
void test (void) {
CallBack1 (ptr, c); // works
CallBack2 (ptr, ptr); // works, but pointers are memory typed now
CallBack3 (c, d, e); // works
CallBack4 (c, d, e | (f<<8)); // works, but two chars are packed into
// one int parameter
}
The parameter passing method is described in the C51/Cx51
Compiler User's Guide. Refer to this to determine how to change
your function parameters to fit into registers.
-
Refer to Function
Parameters in the Cx51 User's Guide.
-
Refer to Application Note
129: Function Pointers in C51 for a complete discussion of all
the ramifications of using function pointers with the C51
compiler.
SEE ALSO
Last Reviewed: Thursday, February 25, 2021
|