C ++ starts from zero (seven) - what is function

zhaozj2021-02-16  65

Where did you perform from the beginning of the program? C forcibly specify, you should define a function called Main in the source file, and the code starts from this function. It should be noted that since C is implemented by the compiler, it is very strong, so the compilers have provided additional program entry points definition syntax (the program entry point is the function that starts), Such as VC, in order to write a DLL file, there should be a main function; in order to write Win32-based programs, you should use WinMain instead of main; and VC actually provides a more flexible means, it can actually let the program start executing from any function. Not necessarily, WinMain, Main, etc., which is the previous WinMain, Main, etc., "C begins with zero (19)". For later instructions, you should know that the program starts running from the main function, as follows: long a; void main () {short b; b ;} long c; actually executing Long a; and long c; but not The actual meaningful statement is from Short B; start. Function machine hand welding the welding point on the car frame, gives the three-dimensional coordinates of the weld point, and the machine hand moves the weld gun to the exact position by controlling the motor of each joint. Once the procedure of the welding torch is controlled, once the machine hand welded to 200 points on the car, the coordinates of 200 points can be simply given, and then the previously edited mobile programs will be called, and No need to repeat the code for each move. The above mobile programs can be represented by a function. The function is a mapping element. Like the variable, associate an identifier (ie, a function name) and an address, and there is a type of association and its association, referred to as a function return type. The function and variables are the address of the function. It must be the address of the code. It seems like the label of the previous description, but the label is different, C defines the function as a type, the label is just a pure two-way number, ie The address corresponding to the function name can be modified by type modifiers such that the compiler can generate the correct code to help the programmer book implementation. Since the compiler does not assign memory because the function is defined, the definition of the modifier "&" no longer function is, the same, the definition of the array modifier "[]" can also know that it cannot act on the function, only left The pointer modifier "*" can be, because the function name corresponds to the number of the address type of some function type. The front mobile program can be called 200 times differently because it is very flexible and can change its operational effects according to different situations (points in different locations). In order to deliver information for explanation to the mobile program (ie, the coordinates), there must be something to complete this, in C , this is implemented using parameters, and for this, C provides a type modifier - Function modifier "()". Let us first understand what abstract declared (Abstract Declarator) before explaining function modifiers. Declare a variable long a; (this looks like a variable, will explain their differences later), where long is the type, used to modify the address corresponding to this variable name. When the variable of the declared variable (ie, the previous way) is removed, the remaining thing is called an abstract declaration.

For example: long * a, & b = * a, c [10], (* d) [10]; then the variables A, B, C, and Decorative declaration modifiers are long *, long &, long [10 ], Long (*) [10]. The function modification is linked to the back of the function name, parentheses zero or more abstract declappings to indicate the type of parameters, and the intermediate "," separated. The parameter is some memory (mapped by parameter name), which is used to deliver some of the necessary information to the code corresponding to the function name to achieve the corresponding function. Declare a function as follows: Long * ABC (long *, long &, long [10], long (*) [10]); on top of the same function ABC, its type is long * (long *, long &, long [10 ], long (*) [10]), indicating that the code begins at the corresponding address of this function is required, and four parameters are required, and the type is as above, the return value is long *. The type above ABC is actually an abstract declaration, so you can also follow: Long Ab (long *, long &, long [10], long (*) [10]), short, long &); for the previous movement The program can be declared as follows: Void Move (Float X, Float Y, Float Z); the parameter name is added when writing declaration modifiers to represent the mapping of the corresponding parameters. However, since it is a statement of functions, the above parameter name does not generate any mapping, as this is a declaration of functions, not defined (regarding declaration, will be explained later). And here is a parameter name is a semantic manifest, indicating that the first, second, and three parameters represent the X, Y, Z coordinate values, respectively. The back of the above is Void, the front mentioned, Void is a special digital type provided by C , which is just to ensure the rigor of the syntax, that is, any function is executed back a number (later will be explained), and For functions that don't have to return numbers, you can define the return type to Void so that the syntax can be guaranteed. It should be noted that any type of number can be converted to a VOID type, that is, (VOID) (234); or void (a); Note that there is no abstract modifier in the above function modifier, that is, Void ABC () ;. It is equivalent to void abc (void); indicating that the ABC does not have a parameter and does not return a value. Then, their abstract declarations are void () or void (void), which can be as follows: long * ABC (long * (), long (), long [10]); it can be seen by the meaning of the function modifier Like the reference modifier, the type of modification cannot be repeated, that is, no Void A () (long); this is meaningless. Similarly, since the type modifier from the left chart, there is also normal: VOID (* pa) (). Assume that this is a variable definition statement (can also be regarded as a statement statement, which will be described later), indicating that the compiler is assigned a 4-byte space on the stack, map this address and PA, and its type is no parameters. , The pointer of the function of the return value of the value is Void. What is the use? It will be explained later.

The function definitions the function definition below, for the previous machine hand control program, can write as follows: void move (float x, float y, float z) {float temp; // According to the value of x, y, z to move the torch } int main () {float x [200], y [200], z [200]; // Put 200 points of coordinates in the array x, y, and z in For (unsigned i = 0; i <200; i ) Move (x [i], y [i], z [i]); Return 0;} The upper surface defines a function Move, its corresponding address is defined statement float temp; the address, but actually due to compiler To help us generate some additional code (called function prefix --Prolog, "C is described in" C ) to obtain the value of the parameter or other work (such as abnormal processing, etc.), so Move will correspond At the FLOAT TEMP; the previous address. The post-touch type modifier is a bit changed before, just add the variable name to make it not an abstract declaration, its role is to let the compiler generate a map, will add the address of the variable name and the address of the corresponding information. Binding, the so-called parameters are formed. Due to this reason, you can write: Void Move (Float X, Float, Float Z) {}. Since the variable name is not bind to the second parameter, the second parameter will not be used, and the meaning will be illustrated later. The definition of the function is the same as the declaration of the previous function, but must be written back to a composite statement (must be a composite statement, that is, the statement enclosed by "{}", this composite statement is the address and this function Name binding, but due to the previously mentioned function prefix, the function name actually corresponds to the address of the composite statement. In order to call a given function, C provides function operators "()", the front of the front function type, and the number and number of the corresponding type according to the parameter type and number of the corresponding functions, so the above MOVE (x [i], y [i], z [i]); use the function operator, use x [i], y [i], z [i] value as a parameter, and record the current location The address that jumps to the corresponding address of Move continues, when returns from the Move, the execution of the subsequent code is processed according to the previously recorded position. Due to the operator, it is also necessary to return a number, that is, the return value of the function, that is, the following: float ab (float x) {return x * x;} int main () {float c = ab (10) Return 0;} First define the function AB, which returns the number of the float type, where the returnite statement is used to indicate the return value of the function, and the subsequent numbers must be the return value type of the corresponding function, and when the return type When you are void, you can write Return directly ;. Therefore, the value of C is 100, the value returned by the function operator is the number returned in the expression x * x of the AB function, and AB (10) will 10 as the value of the parameter X of the AB function, so x * x returns 100. Since the function can have a pointer, the function and variables are compared, and the function name is directly written, such as: ab;

The above will return the number of the address type corresponding to the AB, and then calculate this address type number, it should be the content of the memory corresponding to the corresponding address, consider the meaning of the function, and it will be meaningless, so it does not make Anything, directly returning the number of binary numbers corresponding to this address type, which is equivalent to the first pointer type. Therefore, it is also possible to: int Main () {float (* pab) (float) = ab; float c = (* pab) (10); return 0;} The top is defined on the top, which is float. *) (FLOAT), assigns the address corresponding to the AB to it at first. Why not write a PAB = & ab; but PAB = AB;? Because the number of the address type of the function type will not do anything, the effect is the same as the number of the pointer type, so PAB = AB; there is no problem, and Pab = & ab; there is no problem. The digital compiler of the address type of the function type can be considered to be implicitly converted to the number of the pointer type, so it can be either (* pab) (10); or (* ab) (10); because the latter compiler Implicit type conversion. Since numbers are connected in the function operator, FLOAT C = Ab (ab (10)) can also be, i.e., C is 10000. It should also be noted that the function operator allows the compiler to generate some code to deliver the value of the parameter and the jump to the corresponding address to continue executing the code, so as follows: long ab (long x) {if (x> 1) Return X * Ab (x - 1); Else Return 1;} The above means that when the value of the parameter X is greater than 1, the number returned by X -1 is used as a parameter, then jumps to the address corresponding to AB, that is, if (x> 1) The corresponding address is repeated. So if LONG C = Ab (5);, C is 5 steps. If it is not understood above, the detailed description of the function is implemented, as well as the so-called stack overflow problem. It should now know the meaning of the main function, just establish a mapping, so that the connector makes the portal address of the program, that is, the address corresponding to the main function. The above function Move is defined before the function main, and if the definition of Move is moved below, the error will occur, and the function move is not defined, why? Because the compiler is compiled from the top and is only compiled once. What should I do? Next description. The mobile function in front of the overload function, if you only want to move the X and Y coordinates, in order not to move the Z coordinate, you must write a function as follows: Void Move2 (Float X, Float Y); it is not with the previous Move function Name conflicts change to Move2, but Move2 also means moving, but it is not to change a name, which seriously affects semantics. In order to better exhibit semantics from the source code, the meaning of this code, C proposes the concept of overload function. The overload function represents the name of the function name, but multiple functions of the parameter type and number of numbers.

The two overload functions are defined as follows: Void Move (Float X, Float Y, Float Z) {} and void move (float x, float y) {}, which define two overload functions, although the function name is the same, but actually two functions, The function name is the same indicates that they have the same semantic-moving welding gun, but the moving mode is different, the former moves in the three-dimensional space, the latter moves on a horizontal plane. When Move (12, 43); time calls the latter, and Move (23, 5, 12); when you call the former. However, it must be different from the parameters. It cannot be different from the return value, that is, the error will be reported below: float move (float x, float y) {return 0;} and void move (float a, float b) {} above although return value Different, but the compiler still believes that the function of the above definition is the same, the function is repeatedly defined. why? Because the return value type of the function cannot be guaranteed when writing the function operator, Float A = Move (1, 2); although it can be launched, it should be the former, but can also move (1, 2); Know which function should be used, so it will not. It should also be noted that although the above parameter name is different, it is the same, the parameter name is only indicated in the scope of the function, and will be explained later. There is no problem as follows: float move (float x, float y) {return 0;} and void move (float a, float b, float c) {} should also pay attention to the following questions: float move (float x, char Y); float move (float a, short b); Move (10, 270); The above compiler will report an error because 270 here will be considered int, ie integrity when calculating the function operator, ie integrity, it can turn It can also be converted to a short, and the compiler will not be able to determine which function should be. To this end, you should move (10, (char) 270) ;. Declaration and definition declarations are some information to tell the compiler to assist the compiler to perform grammatical analysis and avoid compiler error. The definition is to tell the compiler to generate some code, and these code will be used by the connector. That is: The declaration is for the compiler, defined is used for the connector. This note is very vague, why do you have to make a statement and definition? It is because C agrees to write the program into several sections, respectively, respectively, respectively, respectively, and the compiler mentioned above is compiled from top, and is compiled only once for each file. When compiling the compiler, only one source file is compiled and generate the corresponding intermediate file (the VC is the .Obj file), and then the connector is unified to connect all intermediate files to form an executable file. The problem is that the compiler is compiled when compiling a.cpp files, and the variables A and B are discovered by the definition statement, while when compiling B.CPP, discover code using A and B, such as A = B;, but in B. The definition statement of A and B is found in the CPP, and the compiler will report an error.

why? If you don't report an error, it is defined because of A.cpp, then compile B.CPP and compile A.CPP? If the compilation order of the source file is specific, it will greatly reduce the flexibility of compilation, so C also specifies: all things (variables, functions, functions) defined when compiling a.cpp, will not count when compiling B.cpp, Just as there is no compiled A.cpp. So what should I do if b.cpp uses a variable defined in A.CPP? To this end, C made a declaration of this concept. Therefore, the variable declarations long a; it is telling the compiler that there is such a variable, its name is a, its type is long, its corresponding address does not know, but you can make a mark first, that is, this variable in subsequent code The logo is made to tell the connector, when you are connected, you will find a variable called A in all intermediate files. The address is how much, then modify all the logo, the address corresponding to put in. This enables this file to use variables defined in another file. So declare the long a; it is to tell the compiler already have such a variable A, so when you use A in subsequent code, don't report an error. A is not defined. The same is true, but there is a problem is that the function declaration and function definition is easy to distinguish, because the function definition must be a complex statement, but the variable definition and variable declaration is exactly the same, how will the compiler identify variable definitions and variable declarations? When the compiler encounters long a; when it is uniformly considered to be variable definitions, in order to identify variable declarations, the modifier Externs proposed by C can be used. The modifier is a statement or definition of the statement to modify this declaration or definition to provide a certain information to the compiler, which is always connected in front or behind the declaration or definition statement, such as: Extern long a, * pa, & ra The above is declared (not defined) three variables A, PA, and RA. Because extern represents the external meaning, it is considered to tell the compiler with three external variables, which is A, PA, and RA, so it is considered to be a statement statement, so it will not be assigned any memory. Similarly, for functions, it is also the same: extern void abc (long); or Extern long AB (short b); the above EXTERN is equivalent to not writing, because the compiler is based on the final ";" can judge that the above is a function Declaration, and the information provided "outside" is meaningless for functions, and the compiler will not pay attention. Externally also specifies the modification of the identifier after the decoration, actually should be extern "c" or extern "C ", which represents the identifier of the declared declaration according to the C language style and C language style. C is a strong type of language, which is required to have a strict type matching principle, which in order to achieve the previous function overload function. That is, a few of the same name functions are re-loaded because they do not actually have a name, and the individual parameter types and numbers have become different. Such as Void ABC (), * ABC (long), ABC (long, short); in VC, its respective names will be "? ABC @@ Yaxxz", "? ABC @@ yapaxj @ z", "? ABC @@ yaxjf @ z".

The name of the three variables of Extern Long a, * Pa, & Ra; "? A @@ 3ja", "? Ra @@ 3paja", "? Ra @@ 3paja", "? Ra @@ 3paja", "? It is called the C language style identifier in the C language style (different compiler modified formats may be different), while C language style identifier modifications are just simple in the identifier, "_" (different compilers) C style modification will be identical). Such as: extern "C" long a, * pa, & ra; turn _A, _PA, _RA. And the above Extern "C" void abc (), * abc (long), ABC (long, short); will report an error, because using a C style, just add a crowline before the function name, will result in 3 identical symbols (Symbol), error. Why can't you have the same symbol? Why change the identifier? Not only because of the previous function overload. The symbols and identifiers are different, and the symbols can be composed of any character, which is a means of communication between the compiler and the connector, and the identifier is only a logo means provided on the C language level. The reason why you want to change the identifier without directly using the identifier as a symbol because there are some information between the compiler yourself and the connector needs to be passed, which requires the symbol to identify, due to the identifier written by the user Just as the symbol inside the compiler, the same conflict is the same, so they must be modified on the identifier defined by the programmer. Since the symbol is what characters can, why does the compiler do not allow the symbols inside to use the characters that identifies cannot be used, as "?" "?", That isn't it? " Because some C / C compilers and connector communication are not what characters can be, it must be an identifier, so the front C language style is unified plus "_" prefix to distinguish the programmer defined symbol And the symbol inside the compiler. That is, "?" To use "?" As a symbol is VC, maybe other compilers do not support, but other compilers must support the identifier of the "_" prefix. This can be used in combination with multi-square code to implement code reuse on a larger range, and will be described in detail in "C from zero (18)". When writing extern void abc (long); is EXTERN "C" or EXTERN "C "? In the VC, if the extension of the source file where the presentation code is located is .cpp, it will be explained to the latter. If it is .c, it will be explained as the former. However, the above default settings can be changed by modifying the item options in the VC. And extern long a; also is the same. So the following: Extern "C " void ABC (), * ABC (long), ABC (long, short); int main () {abc ();} The first sentence told the compiler Subsequent code may be used Three functions, called compilers do not report error. Suppose the above program is placed in a.cpp under a VC project, compiling A.CPP will not have any errors. But when connected, the compiler will say symbol "ABC @@ yaxxz" did not find because this project contains only one file, and the connection is only connected to the corresponding A.Obj and some other necessary library files (subsequent articles) It will be explained).

What is the address that the connector finds a symbol "? ABC @@ Yaxxz" in all object files it can connect, and the address of the symbol "ABC @@ yaxxz" is not found, it is wrong. In other words, the main function uses a function void ABC () defined outside A.CPP;, but did not find the definition of this function. It should be noted that if Int main () {void (* pa) = ABC;} is still an error, because ABC is equivalent to an address, here is required to calculate the value of this address (even if it does not use PA), it will also report an error . In order to eliminate the above errors, the function void abc () should be defined; either in A.CPP, such as behind the main function, can also regenerate a .cpp file, add to the project, in that .cpp file Define function ABC. So as follows: Extern "C " void ABC (), * ABC (long), ABC (long, short); int main () {abc ();} void abc () {} If you think you have already understood The difference between declaration and definition, and clear the meaning of the statement, then I have a 50% possibility that you don't really understand the meaning of the statement. Here, it will be described in "C from scratch (ten)". The true meaning of the statement, if you are some C / C programming experience, the sample given by 50% will make you a shock. Calling the rule call rule finger means how to pass, how to return the value, and how the above function name identifier is modified. It does not belong to the content of the language, because it indicates how the compiler implements functions, and each compiler has its own processing. In VC, it defines three type modifiers to inform the compiler to implement function, respectively: __ cdecl, __ stdcall and __fastcall. Three have different parameters, function return value transmission mode and function name modification, and later explain the exception, the specific implementation method of the function will be explained again. Since they are type modifiers, they can be modified as follows: void * __ stdcall abc (_), __fastcall de (), * (__stdcall * pab) (_) = & abc; void (__fastcall * pde) () = de; variable The role domain defines the function move, saying void move (float a, float b); and void move (float x, float y); which is the same, that is, the variable name a and b have no significance. This means that the scope of the variables A, B is limited to the previous Move functional body (ie, the composite statement when the function is defined), and the effective range of the same X and Y is only in the back MOVE function body. This is called a variable. //a.cpp//long e = 10; void main () {short a = 10; E ; {long E = 2; E ; A ;} E ;} The effective range of the first E above is the entire A In the .cpp file, the effective range of A is in the main function, and the effective range of E in the main function is included in "{}".

转载请注明原文地址:https://www.9cbs.com/read-17050.html

New Post(0)