# Include <iostream>
# Include <cstdio>
IntMain ()
{
IntArr [] = {6, 7, 8, 9, 10 };
Int* PTR = arr;
* (PTR ++) + = 123;
// Printf ("% d, % d, % d \ n", * PTR, * (++ PTR), * PTR); // 8, 8, 7
// STD: cout <* PTR <"," <* (++ PTR) <"," <* PTR <STD: Endl; // 7, 8, 8
// Printf ("% d, % d, % d \ n", * PTR, * (PTR ++), * PTR); // 8, 7, 7
STD: cout <* PTR <","<* (PTR ++) <","<* PTR <STD: Endl;// 7, 7, 8
For(IntI = 0; I <5; ++ I)
{
STD: cout <arr [I] <"\ T";
}
}
If you cannot understand the output result, consider the following two aspects:
- Operator priority and associativity
- Parameter transfer sequence and call conventions
- Important:Expression value !!Expressions can be divided into subexpressions.
In the preceding example.
* (I ++)
Although you use parentheses to forcibly calculate I ++ first, you must recognize the essence. The I ++ expression is actually equivalent
Int TMP = I;
// Do other operation, take the rvalue of TMP as the rvalue of expression (I ++) for other use
I = I + 1;
A temporary variable is generated as the value of the I ++ expression. That is, the value of the I ++ expression is the value of the temporary variable that saves the original I value.
In fact, * (I ++) and * I ++ have the same effect, because ++ has a higher priority *
Question 1: computing priority
For complex operation sequence problems, determine the Operation SequenceAlgorithmAs follows:
1. First find all operatorsLowest priorityThe expression is divided into multiple segments based on the boundary operators. Each segment is enclosed by parentheses ()
2. Considering the order of combination for the same priority
3. the compiler scans the operation sequence from left to right (??)
Therefore, we should analyze the expression operation from left to right, and compare it with the priority of the near operator, and add parentheses to make it clearer. After the analysis is complete and parentheses are added, you can consider the order of associativity, from left to right or from right to left.
In fact, the entire analysis process is also the process of compiler analysis, but the compiler generates a multi-Cross Tree. The manually added brackets correspond to the branches on the tree.
Instance analysis:
! X & x + y ++-y;
First, find the lowest priority among all operators and divide the expressions into multiple segments based on these operators.
& Minimum priority
(! X) & (x + y ++-y );
The second half of the analysis, +,-lowest priority
(! X) & (x) + (Y ++)-(y ));
You can try another example:
X-++ y + x> Y? X ++: X % Y --/x + 1
(X-++ y + x> Y )? (X ++) :( X % Y --/x + 1)
(X-++ y + x)> Y )? (X ++) :( (X % Y --/x) + 1)
(X)-(++ y) + (x)> Y )? (X ++) :( (x) % (y --)/x) + 1)
Finally, a good programming style can completely avoid these complex and complex computing priority problems. We recommend that you add parentheses to a complex expression.
Note: The operator priority in C ++ and C is different. The following is the operator priority of C. It can be seen that ++ and * are at the same priority.
Therefore, see CProgramDesign Language p79
Question 2: parameter transfer and call conventions
First, let's talk about the parameter transfer direction and stack clearing problems related to the call conventions.
_ Stdcall, _ cdecl, _ fastcall,... functions modified by these modifier keywords, whose parameters areFrom right to left Passed through the stack (the first part of _ fastcall is passed by ECx and EDX ),
The stack should be cleared before function calls are returned, but it is not necessarily cleared by the caller.
1. _ stdcall is the default calling method of the PASCAL program. It is usually used in Win32 APIs. The function uses the stack pressure mode from right to left,
Clear the stack when you exit. After compiling a function, VC adds an underline prefix to the function name, and adds "@" and the number of bytes of the parameter to the function name. Int F (void * p) --> _ f @ 4 (this function can be referenced in an external assembly language)
2. The _ cdecl and C call conventions (the C default calling convention) press the parameters from right to left into the stack, and the caller pushes the parameters to the stack. The memory stack of the transfer parameter is maintained by the caller (because of this, the variable parameter vararg function (such as printf) can only use this call Convention ). In addition, the function name modification conventions are also different. _ Cdecl is the default call Method for C and C ++ programs. Every function that calls it contains Code Therefore, the size of the executable file is larger than that of the _ stdcall function. The function uses the stack pressure mode from right to left. After compiling a function, VC adds an underline prefix to the function name.
Is the default MFC call convention.
3. _ fastcall is fast because it transmits parameters through registers (in fact, it uses ECx and EDX to transmit the first two Dwords) for smaller parameters, the remaining parameters are still transmitted from the right to the left pressure stack, And the called function clears the memory stack of the transferred parameter before returning). In terms of function name modification conventions, it is different from the previous two. _ Fastcall: The function uses registers to pass parameters. After compiling the function, VC adds the "@" prefix to the function name, add "@" and the number of bytes after the function name.
4. thiscall is only applied to "C ++" member functions. This pointer is stored in the CX/ECx register, and the parameter is pressed from right to left. Thiscall is not a keyword and cannot be specified by programmers.
5. Naked call. When 1-4 calls are adopted, the compiler will generate code to save ESI, EDI, EBX, and EBP registers when entering the function if necessary, when you exit the function, the code is generated to restore the content of these registers.
(These codes are called PROLOG and epilog code. Generally, the storage of EBP and ESP is required ).
However, naked call does not generate such code. The naked call is not a type modifier, so it must be used together with _ declspec.
The keywords _ stdcall, _ cdecl, and _ fastcall can be directly added before the function to be output. Their corresponding command line parameters are/GZ,/GD, And/GR. The default status is/GD, Which is _ cdecl.
To fully imitate Pascal's call convention, you must first use the _ stdcall call Convention. As for the function name Modification Convention, you can use other methods to imitate it. Another thing worth mentioning is winapi macro, windows. h supports this macro. It can translate the function into an appropriate call convention. In Win32, it is defined as _ stdcall. You can use the winapi macro to create your own APIs.
2) Name modification conventions
1. decoration name)
The "C" or "C ++" functions are identified by modifier internally (Compilation and link. Modifier is a string generated by the compiler when compiling a function definition or prototype. In some cases, modifying the name of a function is necessary, for example, specifying the output "C ++" overload function, constructor, and destructor in the module definition file, for example, call the "C" or "C ++" function in the assembly code.
Modifier names are jointly determined by function names, class names, call conventions, return types, parameters, and so on.
2. The name Modification Convention varies with the call convention and the compilation type (C or C ++. The function name modification conventions vary with the compilation type and call conventions.
Rules for modifying function names during a and c Compilation:
_ Stdcall: add an underline prefix before the output function name, followed by the "@" symbol and the number of bytes of its parameters,
The format is _ functionname @ number.
The _ cdecl call Convention only adds an underline prefix before the output function name in the format of _ functionname.
_ Fastcall: Add a "@" symbol before the output function name, followed by a "@" symbol and the number of bytes of its parameters,
The format is @ functionname @ number.
They do not change the case sensitivity of the output function name. This is different from Pascal's call conventions. Pascal's output function names are not modified and all are capitalized.
B. Conventions for function name modification during C ++ Compilation:
_ Stdcall call conventions:
1. Take "?" Start of the function name, followed by the function name;
2. The parameter table starts with "@ YG" after the function name, followed by the parameter table;
3. The parameter table is represented in code:
X -- void,
D -- char,
E -- unsigned char,
F -- short,
H -- int,
I -- unsigned int,
J -- long,
K -- unsigned long,
M -- float,
N -- double,
_ N -- bool,
....
Pa -- indicates the pointer, and the code behind it indicates the pointer type. If a pointer of the same type appears consecutively, it is replaced by "0", which is a "0" generation.
The table is repeated once;
4. the first item of the parameter table is the type of the return value of the function, followed by the Data Type of the parameter. The pointer ID is before the Data Type
;
5. mark the end of the entire name with "@ Z" after the parameter table. If this function has no parameter, it ends with "Z.
The format is "? Functionname @ YG ***** @ Z "or"? Functionname @ YG * xz ", for example
Int test1 (char * var1, unsigned long) ----- "? Test1 @ yghpadk @ Z"
Void Test2 () ----- "? Test2 @ ygxxz"
_ Cdecl:
The rules are the same as the _ stdcall call Convention above, except that the start mark of the parameter table is changed from "@ YG" to "@ ya ".
_ Fastcall:
The rules are the same as the _ stdcall call Convention above, but the start mark of the parameter table is changed from "@ YG" to "@ Yi ".
The "_ cedcl" Declaration for the function can only be called by C/C ++.
6 usage example
Bool _ declspec (dllexport) _ stdcall installhook ()
{
Hkb = setwindowshookex (wh_keyboard,
(Hookproc) keyboardproc,
Hins,
0 );
Return true;
}
The specific function name Modification Convention should be related to the compiler. You can view another log in detail ..