Home>

Usual function callAn example of a normal function call:

//Include header files by yourself
void myfun (int x);//The declaration here can also be written as:void myfun (int);
int main (int argc, char * argv [])
{
  myfun (10);//here is the call to myfun (10);function
   return 0;
}
void myfun (int x) //This defines a myfun function
{
  printf ("%d \ n", x);
}

This myfun function is a function with no return value,It doesn't accomplish much.You should be familiar with this format of calling functions! See the writing format of the myfun function in the main function:

myfun (10);

At the beginning, we only understood the function myfun from a functional or mathematical sense.Know that myfun function name represents a function (or a piece of code).

until--

When you learn the concept of function pointers.I just had to think:what exactly is a function name?

(Do n’t think it ’s meaningless! Oh, keep looking down and you will know.)

Declaration of function pointer variables

Just as the memory address of a data variable can be stored in the corresponding pointer variable,The first address of a function is also stored in a function pointer variable.In this way, I can call the function pointed to by this function pointer variable.

In the c-series languages,Any variable,Always declare first,Can only be used later.So, function pointer variables should also be declared first?So how do you declare it?Take the above example as an example,Let me declare a function pointer variable funp that can point to myfun function. Here's how to declare the funp variable:

void (* funp) (int);//can also be written as void (* funp) (int x);

You see, the declaration format of the entire function pointer variable is the same as the declaration of the function myfun.It's just-we changed myfun to (* funp), so we have a pointer funp that points to the myfun function. (Of course, this funp pointer variable can also point to all other functions with the same parameters and return value.)

Calling functions through function pointer variablesWith the funp pointer variable,We can assign it to point to myfun, and then call myfun function through funp. See how I call myfun function through the funp pointer variable:

//Include header files by yourself
void myfun (int x);//This declaration can also be written as:void myfun (int);
void (* funp) (int);//Can also be declared as void (* funp) (int x), but this is generally not the case.
int main (int argc, char * argv [])
{
  myfun (10);//This is the direct call to myfun function
  funp =&myfun;//Assign the address of myfun function to the funp variable
  (* funp) (20);//This is the function myfun called through the function pointer variable funp.
}
void myfun (int x) //This defines a myfun function
{
  printf ("%d \ n", x);
}

See the code and comments in boldface.

Run and see.Well, yes, the program works just fine.

Oh, my feeling is:the type relationship between myfun and funp is similar to the relationship between int and int *. The function myfun seems to be a variable (or constant) like int, while funp is like a pointer variable like int *.

int i, * pi;
pi =&i;//Compare with funp =&myfun.

(How do you feel?)

Ha ha, actually not--

Other writing formats for calling functions

Function pointers can also be used as follows,To accomplish the same thing:

//Include header files by yourself
void myfun (int x);
void (* funp) (int);//Declare one to point to the same parameter,A pointer variable to a return value function.
int main (int argc, char * argv [])
{
  myfun (10);//here is the call to myfun (10);function
  funp=myfun;//Assign the address of myfun function to the funp variable
  funp (20);//This is to call the myfun function through the function pointer variable.
   return 0;
}
void myfun (int x) //This defines a myfun function
{
  printf ("%d \ n", x);
}

I changed the bold type part (please compare it with the previous code yourself).

Try it out,what! Just as successful.

Huh?

funp=myfun;

You can assign myfun value to funp in the same way. Is myfun and funp the same data type (ie, the relationship between int and int), not the relationship between int and int *?(Are you a little confused?)

It seems a bit contradictory to the previous code,right! So what do I say!

Please allow me not to explain it to you for the time being.Continue to look at the following situations (these are all code that can run correctly!):

Code three:

int main (int argc, char * argv [])
{
  myfun (10);//here is the call to myfun (10);function
  funp =&myfun;//Assign the address of myfun function to the funp variable
  funp (20);//This is to call the myfun function through the function pointer variable.
   return 0;
}

Code four:

int main (int argc, char * argv [])
{
  myfun (10);//here is the call to myfun (10);function
  funp=myfun;//Assign the address of myfun function to the funp variable
  (* funp) (20);//This is to call the myfun function through the function pointer variable.
   return 0;
}

It really can be like this!

(Wow! I'm going to faint!)

And there! Look--

int main (int argc, char * argv [])
{
  (* Myfun) (10);//Look, the function name myfun can also have this calling format
   return 0;
}

You may see it for the first time:the function name call can also be written like this! (It's just that we usually don't write like this.)

So what does all this mean?

Ha ha! If I were "Holmes", and based on my previous knowledge and experience to reason about the "new findings" in this article, I would definitely analyze and infer the following conclusions from this:

1. In fact, the function name of myfun and the funp function pointer are the same,That is, function pointers.myfun function name is a function pointer constant,And funp is a function pointer variable,This is their relationship.

2. But if the function name is called as (* myfun) (10);in this way, writing and reading are inconvenient and unaccustomed.Therefore, the designers of the C language will design it to allow myfun (10);this form of calling (this is much more convenient and the same as the function form in mathematicsIsn't it?).

3. For the sake of uniformity,Funp function pointer variables can also be called in the form of funp (10).

4. When assigning values, you can use funp =&myfun, or funp=myfun.

The above code is written,Whatever you love!

Please understand it this way! This is helpful for your application of function pointers!

At last--

One additional note:In the declaration of the function:

void myfun (int);//Cannot be written as void (* myfun) (int).
void (* funp) (int);//Cannot be written as void funp (int).

(See note) This is something to be aware of.

Define the pointer type of a function:

Just like custom data types,We can also first define a function pointer type,Then use this type to declare function pointer variables.

Let me give you an example of a custom data type.

typedef int * pint;//An alias for pint is defined for type int *
int main ()
{
 int x;
 pint px =&x;//is equivalent to int * px =&x ;.
The pint type is actually an int * type
 * px=10;//px is a variable of type int *
 return 0;
}

According to the comment,It should not be hard to understand! (Although you may rarely use this definition,But I will often see this when I learn win32 programming.)

Let ’s take a look at the definition and use of function pointer types:

//Include header files by yourself
void myfun (int x);//The declaration here can also be written as:void myfun (int);
typedef void (* funtype) (int);//This just defines a function pointer type
funtype funp;//then use funtype to declare global funp variables
int main (int argc, char * argv [])
{
//funtype funp;//Of course, function pointer variables can also be local, so please declare here.
  myfun (10);
  funp =&myfun;
  (* funp) (20);
   return 0;
}
void myfun (int x)
{
  printf ("%d \ n", x);
}

Look at the bold part:

First, a typedef is added before void (* funtype) (int) ;. This just defines a function pointer type called funtype,Instead of a funtype variable.

Then, funtype funp;declares a funp variable like pin px ;.

Others are the same.The entire procedure accomplishes the same thing.

The benefits of this approach are:

With the funtype type, we can also use the funtype type to declare multiple function pointer variables of the same type.as follows:

funtype funp2;
funtype funp3;
//……

Function pointers as arguments to a function

Since the function pointer variable is a variable,Of course, it can also be used as a parameter of a function.Therefore, you should also know how function pointers are passed as arguments to a function.

Give you an example:

Requirement:I want to design a callmyfun function. This function can call the three functions myfun1, myfun2, and myfun3 respectively according to the function pointer values ​​in the parameters. (Note:the definition format of these three functions should be the same).

Implementation:The code is as follows:

//Include header files by yourself
void myfun1 (int x);
void myfun2 (int x);
void myfun3 (int x);
typedef void (* funtype) (int);//②. Define a function pointer type funtype, which is the same as ① function type
void callmyfun (funtype fp, int x);
int main (int argc, char * argv [])
{
  callmyfun (myfun1,10);//⑤. Call three different functions through callmyfun function
  callmyfun (myfun2,20);
  callmyfun (myfun3,30);
}
void callmyfun (funtype fp, int x) //③. The type of parameter fp is funtype.
{
 fp (x);//④. Execute the function passed in through the pointer of fp,Note that the function pointed to by fp has one parameter
}
void myfun1 (int x) //①. This is a function with one parameter,The following two functions are also the same
{
  printf ("Output from function myfun1:%d \ n", x);
}
void myfun2 (int x)
{
  printf ("Output from function myfun2:%d \ n", x);
}
void myfun3 (int x)
{
  printf ("Output from function myfun3:%d \ n", x);
}

Output:slightly

Analysis:(See the notes I wrote.You can analyze by yourself in the order of ①②③④⑤ as I explained.)

Address jumpvoid (* reset) (void)=(void (*) (void)) 0.

void (* reset) (void) is the function pointer definition,(void (*) (void)) 0 is a cast operation,The value "0" is coerced to the function pointer address "0".

By calling the reset () function, the program will jump to the "0" address of program execution and execute again.In some other advanced microcontroller bootloaders, such as nboot, uboot, and eboot, these bootloaders are often used to download programs.Then use the function pointer to jump to the address of the program to be executed.

1 void (* theuboot) (void);

. . . .

theuboot=(void (*) (void)) (0x30700000);

theuboot ();

. . . . .

2 (* (void (*) (void)) (0x30700000)) ();

Coercion,Convert an absolute address into a function pointer,And call this function to jump to the absolute address mentioned earlier.

Translated into compilation is:

mov r0,0x30700000;

mov pc, r0

For (* (void (*) (void)) (0x30700000)) ();

Can be understood like this

First of all (void (*) (void)) is a castHe casts the following unsigned integer 0x30700000 into a function pointer,The function pointer pointed to by the function pointer is void, and the return value is also void. If you understand at this step,Then let (void (*) (void)) (0x30700000) be fp;then the above expression can be simplified to (* fp) ();We reference the converted function pointer above (that is, call the function pointed to by the function pointer).

Right-left rule

C language has complex pointer declarations,All are made up of nested declarations.Comprehend complex pointer statements often appear in written questions from major companies.The right-left rule is a well-known and commonly used method.

the right-left rule:start reading the declaration from the innermost parentheses, go rigtht, and then go left. when you encounter parentheses, the direction should be reversed. once everything in the parentheses has been parsed, jump out of it. continue till the whole declaration has been parsed.

Right-left rule:Look at the inner brackets first,Then look to the right,Look left.Whenever parentheses are encountered,You should reverse your reading direction.Once everything in the parentheses is parsed,Just jump out of the parentheses.Repeat this process until the entire statement is parsed.

Example

 int (* func) (int * p);

First find the undefined identifier,Is func, which has a pair of parentheses on the outside,And on the left is a *, which means that func is a pointer.Then jump out of parentheses,Looking at the right, it is also a parenthesis,This means that (* func) is a function,And func is a pointer to this kind of function,That is a function pointer.This type of function has parameters of type int *,Return type is int

 int (* func) (int * p, int (* f) (int *));

func is enclosed by a pair of parentheses,And there is an * on the left, indicating that func is a pointer,Then jump out of this parenthesis,Look at the right,Is also a parenthesis,Note that func is a function pointer.This type of function has parameters like int * and int (*) (int *),The return value is int. For the parameters of int (* f) (int *), the analysis method is the same as func

 int (* func [5]) (int * p);

To the right of func is a [] operator, indicating that func is an array with 5 elements.Func has a * on the left, indicating that the element of func is a pointer,Note that the * here is not a func, but a func [5], because the [] operator has higher priority than *, and func is combined with [] first, so * modifies func [5]. This bracket,Looking at the right, it is also a pair of parentheses,The elements of the func array are pointers to function types,The function it points to has a parameter of type int *,Return type is int

 int (* (* func) [5]) (int * p);

func is surrounded by a pair of parentheses,There is another * on the left, then func is a pointer,Out of parentheses,On the right is a [] operator,Note that func is a pointer to an array,Looking left now,There is a * on the left, indicating that the elements of this array are pointers,Jump out of the brackets,Looking to the right, there is another parenthesis on the right,Indicates that the elements of this array are pointers to functions.To sum it up:func is a pointer to an array,The elements of this array are function pointers,These pointers have int * parameters and return functions of type int

 int (* (* func) (int * p)) [5];

func is a function pointer,This type of function has a parameter of type int *,The return value is a pointer to an array,Points to an array with 5 elements of type int.

c
  • Previous jQuery method to determine whether the image is loaded
  • Next jQuery based on Ajax to implement animated non-refreshing histogram voting code