To understand a CProgramIt is not enough to understand the symbols that constitute the program. Programmers must also understand how these symbols are combined into declarations, expressions, statements, and programs.
Let's take a look at the following statement:
(* (Void (*) () 0 )();
This is a child routine that the hardware will call when the computer starts. An expression like this may make every C/C ++ programmer feel "chilling.
However, there is no fear at all. Any c variable Declaration consists of two parts:Type and a set of declaration operators similar to expressions. The simplest declaration variable, such:
Float F, G;
The meaning of this statement is: when the expression F and G are evaluated, the type of the expression F and G is floating point.
The same logic applies to declarations of function and pointer types, for example:
Float ff ();
The meaning of this statement is: The expression ff () returns a floating point number, that is, FF is a function that returns a floating point type, similar:
Float * PF;
This statement indicates that * PF is a floating point number, that is, PF is a pointer to a floating point number.
These forms can also be combined in the declaration, just as in the expression, so:
Float * g (), (* H )();
* G () and (* H) () are floating point expressions. Because the combination priority of () is higher than *, * g () is * (G (): G is a function, and the return value type of this function is a pointer to a floating point. Similarly, we can conclude that H is a function pointer, And the return value of H pointing to the function is a floating point type.
Once we know how to declare a variable of a given type, the type conversion operator of this type is easy to get: just remove the variable name and semicolon at the end of the Declaration in the Declaration, then, encapsulate the remaining parts with a bracket. For example:
Float (* H )();
Indicates that H is a pointer to a function with a return value of the floating point type. Therefore,
(Float (*)())
Indicates a"Pointer to a function that returns a floating point type..
Now let's look at the expression we mentioned above:
(* (Void (*) () 0 )();
Step 1: assuming that the variable FP is a function pointer, how can we call the function pointed to by FP? The call method is as follows:
(* FP )();
Because FP is a function pointer, * FP is the function pointed to by this pointer, so (* FP) () is the method to call this function.
In the expression (* FP) (), * brackets on both sides of the FP are very important because the priority of the function operator () is higher than that of the single object operator *. If * FP has no parentheses, * FP () actually has exactly the same meaning as * (FP.
The remaining problem is to find a proper expression to replace FP. We will solve this problem in step 2 of the analysis. If the C compiler can understand the types in our brains, we can write as follows:
(* 0 )()
The preceding formula does not take effect, because the operator * must have a pointer for the operand. The pointer should also be a function pointer so that the result after the operator * can be called as a function. Therefore, type conversion must be performed on 0 in the above formula. The converted type can be roughly described as: "pointer to function with return value of void type ".
If FP is a pointer to a function whose return value is void, the value of (* FP) () is void. The FP declaration is as follows:
Viod (* FP )();
Therefore, convert constant 0 to"Pointer to the function whose return value is void"Type, which can be written as follows:
(Void (*) () 0
Therefore, we can replace FP with (void (*) () 0 to get:
(* (Void (*) () 0 )();
Of course, we can use typedef to solve this problem more clearly:
Typedef void (* FP) (); (* (FP) 0 )();
This problem can be solved.
Let's look at the signal library function. Generally, programmers do not manually declare the signal function, but directly use the Declaration in the header file signal. h. So how is the signal function declared in the header file signal. h?
First, let's start with the User-Defined signal processing function, which is undoubtedly the easiest solution. This function can be defined as follows:
Void sigfunc (int n) {/* specific signal processing part */}
The parameter of the sigfunc function is an integer representing a specific signal. We ignore it temporarily.
The previously assumed function body defines the sigfunc function. Therefore, the declaration of the sigfunc function can be as follows:
Void sigfunc (INT );
Now, if we want to declare a pointer variable pointing to the sigfunc function, we may name it SFP. Therefore, SFP points to the sigfunc function. * SFP represents the sigfunc function, so * SFP can be called. Therefore, we can declare SFP as follows:
Void (* SFP) (INT );
Because the return value type of the signal function is the same as the return value type of SFP, the signal function is declared in the above formula. We can declare the signal function as follows:
Void (* signal (something) (INT );
Something here represents the parameter type of the signal function. We also need to know how to declare them. The above statement can be understood as follows: pass an appropriate parameter to call the signal function, unreference the return value of the signal function (which is of the function pointer type), and then pass an integer parameter to call the function after the function is released, the return value is of the void type. Therefore, the return value of the signal function is a function pointer pointing to the void type returned.
So what are the parameters of the signal function ?, The signal function accepts two parameters: an integer signal number and a pointer to a user-defined signal processing function. We have previously defined a pointer to the User-Defined signal processing function SFP:
Void (* SFP) (INT );
The SFP type can be obtained by removing the SFP declared above, namely void (*) (INT ). In addition, the return value of the signal function is a pointer to the User-Defined signal processing function before the call. The pointer type is consistent with the SFP pointer type. Therefore, we can declare the signal function as follows:
Void (* signal (INT, void (*) (INT );
Similarly, using typedef can simplify the above function declaration:
Typedef void (* Handler) (INT); handler signal (INT, Handler );
So, do you understand function pointers now? If you have read this articleArticle, I believe you will have unexpected gains!
References: C traps and Defects