Learn more about function Pointers and rules of left and right in C language

  • 2020-04-02 03:15:16
  • OfStack

Normal function calls
      An example of a common function call:


//Include your own header file
void MyFun(int x); //Void MyFun(int); void MyFun(int);

int main(int argc, char* argv[])
{
  MyFun(10); //Here's calling MyFun(10); function

   return 0;
}

void MyFun(int x) //Here I define a MyFun function
{
  printf( " %dn " ,x);
}

      The MyFun function is a function that returns nothing and does nothing. This method of calling functions should be familiar to you. See the writing format of the call to MyFun function in the main function:
MyFun (10);
      We started off with a functional or mathematical understanding of the function MyFun, knowing that the name of the MyFun function represents a function (or a piece of code).
      Until the -
      When you learn the concept of function Pointers. I had to think: what is a function name?
      Don't think this is a meaningless thing. Ha ha, continue to see below you will know.

Declaration of a function pointer variable
      Just as the memory address of a data variable can be stored in the corresponding pointer variable, the first address of a function is stored in a function pointer variable. This way, I can call the function I'm pointing to from this function pointer variable.
      In the C series, any variable is always declared before it can be used. So, function pointer variables should be declared first, right? So how do we say that? As an example from the above example, let me declare a function pointer variable FunP that can point to the 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 whole function pointer variable is declared in the same format as the function MyFun, except we changed MyFun to (*FunP), so we have a pointer to the function FunP. (of course, the FunP pointer variable can also point to all other functions with the same arguments and return values.)

Functions are called through function pointer variables
      Once we have the FunP pointer variable, we can assign it to MyFun and then call the MyFun function through FunP. See how I call the MyFun function through the FunP pointer variable:


//Include your own header file
void MyFun(int x); //This declaration can also be written as: void MyFun(int);
void (*FunP)(int ); //It can also be defined as void(*FunP)(int x), but this is not customary.

int main(int argc, char* argv[])
{
  MyFun(10); //This is directly calling the MyFun function
  FunP=&MyFun; //Assign the address of the MyFun function to the FunP variable
  (*FunP)(20); //This calls the MyFun function through the function pointer variable FunP.
}

void MyFun(int x) //Here I define a MyFun function
{
  printf( " %dn " ,x);
}

      Please see the code and comments in bold.
      Let's see. Well, yes, the program works fine.
      Well, my feeling is that the type relationship between MyFun and FunP is similar to the relationship between int and int *. The function MyFun is like an int variable (or constant), and FunP is like an int * pointer variable.


int i,*pi;
pi=&i;  //Compare to FunP=&MyFun.

      How do you feel?
      Well, not really

Other writing formats for calling functions
Function Pointers can also be used to do the same thing:


//Include your own header file
void MyFun(int x); 
void (*FunP)(int ); //Declares a pointer to a function that returns the value of the same argument.

int main(int argc, char* argv[])
{
  MyFun(10); //Here's calling MyFun(10); function
  FunP=MyFun; //Assign the address of the MyFun function to the FunP variable
  FunP(20); //This calls the MyFun function through the function pointer variable.

   return 0;
}

void MyFun(int x) //Here I define a MyFun function
{
  printf( " %dn " ,x);
}

I changed the boldface part (please compare yourself to the previous code).
Try it out, ah! Equally successful.
Yi?


FunP=MyFun;

You can assign the value of MyFun to the value of FunP in this way. Are MyFun and FunP the same data type (i.e., the relationship between int and int), instead of the relationship between int and int*? Are you a little confused?
Seems to contradict the previous code, right! So I say!
Without giving you an explanation, please continue to look at the following cases (these can be correctly run code yo!). :
Code 3:


int main(int argc, char* argv[])
{
  MyFun(10); //Here's calling MyFun(10); function
  FunP=&MyFun; //Assign the address of the MyFun function to the FunP variable
  FunP(20); //This calls the MyFun function through the function pointer variable.

   return 0;
}

Code 4:


int main(int argc, char* argv[])
{
  MyFun(10); //Here's calling MyFun(10); function
  FunP=MyFun; //Assign the address of the MyFun function to the FunP variable
  (*FunP)(20); //This calls the MyFun function through the function pointer variable.

   return 0;
}

It can be!
(wow! I'm going to faint!
There are! See -


int main(int argc, char* argv[])
{
   ( *MyFun ) (10); //See, the function name MyFun can also have this call format

   return 0;
}

This is probably the first time you've seen it: function name calls can also be written like this. (it's just that we don't usually write it that way.)
So what does all this mean?
Ha ha! If I were "Sherlock Holmes", based on previous knowledge and experience to deduce this "new discovery", I would be sure to analyze and infer the following conclusions:
1. In fact, the function name of MyFun and the function pointer of FunP are the same, that is, they are both function Pointers. The MyFun function name is a function pointer constant, and FunP is a function number pointer variable, which is their relationship.
2. But if the function name is called, it should be like (*MyFun)(10); Thus, both writing and reading are inconvenient and unaccustomed. So the C designers designed it to allow MyFun(10); Call it this way (this is much more convenient and the same as the function form in mathematics, right?) .
3. For unification, the pointer variable of FunP function can also be called in the form of FunP(10).
4. When assigning a value, you can either use the form FunP=&MyFun or FunP=MyFun.
Write the above code however you like!
Please understand it this way! This will help you to use the function pointer.
The last -
One caveat: in the declaration of the function:


void MyFun(int );  //Void (*MyFun)(int) cannot be written.
void (*FunP)(int );  //Void FunP(int) cannot be written.

(see note) this is something to note.

Defines the pointer type of a function:
Just like custom data types, we can define a function pointer type and then declare a function pointer variable using that type.
Let me give you an example of a custom data type.


typedef int* PINT; //Defines an alias for PINT for the int* type
int main()
{
 int x;
 PINT px=&x; //With the int * p = & x; It's equivalent. The PINT type is essentially an int star
 *px=10; //Px is just an int star variable
 return 0;
}

According to the annotation, should not be hard to understand! (although you may rarely use this definition, you will often see it when you learn to program Win32.)
Let's take a look at the definition and use of function pointer types :(please compare with the above!)


//Include your own header file
void MyFun(int x); //Void MyFun(int); void MyFun(int);
typedef void (*FunType)(int ); //This just defines a function pointer type
FunType FunP; //The global FunP variable is then declared with the FunType type

int main(int argc, char* argv[])
{
//FunType FunP; // Function pointer variables can of course be local   Please state it here.  
  MyFun(10); 
  FunP=&MyFun; 
  (*FunP)(20); 

   return 0;
}

void MyFun(int x) 
{
  printf( " %dn " ,x);
}

Look at the bold part:
First, in the void (*FunType)(int); A typedef is added. This just defines a function pointer type called FunType, not a FunType variable.
And then, FunType FunP;   This sentence is like the px; Declare a FunP variable as well.
Everything else is the same. The whole process does the same thing.
The benefits of doing this are:
Now that we have the FunType, we can easily and easily declare multiple function pointer variables of the same type with the FunType type. As follows:


FunType FunP2;
FunType FunP3;
// ... 

Function pointer as an argument to a function
Since a function pointer variable is a variable, it can also be used as an argument to a function. So, you should also know how the function pointer is passed as an argument to a function.
Here's an example:
Requirements: I am going to design a CallMyFun function that can call MyFun1, MyFun2, and MyFun3, respectively, depending on the value of the function pointer in the parameter.
Implementation: the code is as follows:


//Include your own header file
void MyFun1(int x); 
void MyFun2(int x); 
void MyFun3(int x); 
typedef void (*FunType)(int ); //. Define a function pointer type, FunType, and function type one to
void CallMyFun(FunType fp,int x);

int main(int argc, char* argv[])
{
  CallMyFun(MyFun1,10); //. Through the CallMyFun function to call three different functions
  CallMyFun(MyFun2,20); 
  CallMyFun(MyFun3,30); 
}
void CallMyFun(FunType fp,int x) //The type of parameter fp is FunType.
{
 fp(x);//(4). The function passed in by the pointer to fp is executed, note that the function referred to by fp has a parameter
}
void MyFun1(int x) //This is a function with one parameter, the following two functions are the same
{
  printf( "Function MyFun1 In the output: %dn " ,x);
}
void MyFun2(int x) 
{
  printf( "Function MyFun2 In the output: %dn " ,x);
}
void MyFun3(int x) 
{
  printf( "Function MyFun3 In the output: %dn " ,x);
}

Output result: omitted

Analysis :(look at my notes. You may make your own analysis in the order of of my notes.
 
Above part is reprint netizen to say. The original address is: http://blog.pfan.cn/whyhappy/6030.html
 
 
Address the jump
Void reset (*) (void) = (void) (*) (void) 0.
  Void (*reset)(void) is the function pointer definition, (void(*)(void))0 is the type casting operation, the value "0" to the function pointer address "0".
  By calling the reset() function, the program jumps to the "0" address where the program executes and reexecutes. In some other advanced SCM bootloaders, such as NBoot, UBoot, EBoot, often through these bootloaders to download the program, and then jump to the address of the program to be executed by function pointer.
1     Void theUboot (*) (void);
      .
      TheUboot = (void (*) (void)) (0 x30700000);
      TheUboot ();
      .
2     (* (void (*) (void)) (0 x30700000)) ();
Casts, converts an absolute address to a function pointer, and calls the function to jump to the previously mentioned absolute address.
Translated into compendium:
Mov r0, 0 x30700000;
PC, mov r0
For (* (void (*) (void)) (0 x30700000)) ();
You can think of it this way
First of all (void (*)(void)) is a type casting character that enforces the unsigned integer 0x30700000 to a function pointer to a function whose entry argument is void and the return value is also void. If you understand at this step, then set (void (*)(void))(0x30700000) as fp; Then the above expression can be simplified to (*fp)();     OK, now that's clear, we'll refer to the converted function pointer above.
 

Left right law

The c language has complex pointer declarations, which are made up of nested declarations. The right-left rule is a well-known and commonly used method for understanding complex pointer statements that are frequently used in pen questions from major companies.
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 had been parsed, jump out of it. Continue till the whole declaration has had been parsed.

Right-left rule: start with the innermost bracket, then go right, then left. Whenever you encounter parentheses, you should turn the reading direction around. Once you've parsed everything in the parenthesis, jump out of the parenthesis. Repeat this process until the entire declaration is parsed.

The original author made a correction: instead of starting with parentheses, you should start with an identifier that has never been defined, and you should start with an undefined identifier because there may be more than one identifier in a declaration, but only one undefined identifier

The sample


  int (*func) (int *p); 


The first thing to find is an undefined identifier, which is func, which has a pair of parentheses on the outside and a * on the left, which means func is a pointer. And then I'm going to jump out of the parenthesis, and I'm going to go to the right, and I'm going to go to the parenthesis, and I'm also going to go to the parenthesis, and that tells me that *func is a function, and func is a pointer to this type of function, which is a function pointer. This type of function takes an int* argument and returns an int


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


Func is enclosed by a pair of parentheses, and there is a * on the left, indicating that func is a pointer. This type of function has parameters such as int * and int (*)(int *), and the return value is int. For the parameter of int (*f)(int *), the analysis method is consistent with func


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


Func right is a [] operator, explain func is a has five elements of the array, the left side of the func have a *, illustrate func element is a pointer, attention should be paid to the * here is not modified func, but modified func [5], the reason was that the [] operator priority is higher than *, func to [] first, therefore * modified is func. [5] out of the bracket, look to the right, is also a pair of parentheses, explain func array element is a function of type of a pointer, it refers to the function with a parameter of type int *, the return value type is int


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


Func is surrounded by a pair of parentheses, the left and a *, then func is a pointer, jump out, on the right is a [] sign of operation, the func is a pointer to an array, now look to the left, the left has a *, illustrate the array element is a pointer, jump out again, look to the right, the right and a bracket, illustrate the array element is a pointer to a function. To summarize: func is a pointer to an array whose elements are function Pointers. These Pointers have int * parameters and return functions of type int


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


Func is a pointer to a function with an int * parameter, and the return value is a pointer to an array with five int elements.


Related articles: