Analysis of parameters in function calls
Summary: skyjacker
Contributors: liuxiao, Xiaodong, bahamut, koala,
Http://www.cnpack.org
Cnpack iv qq group: 130970
2007-02-02
(Please indicate the author, source, and integrity of the post)
I. Three basic forms of parameters
Function A (B: integer): integer;
Function A (var B: integer): integer;
Function A (const B: integer): integer;
B: After assigning values to B in the function body, the function does not pass out the function.
VaR B: After assigning values to B in the function body, the function will be transferred out of the function.
Const B: The function body cannot assign values to B.
Ii. Explanation
One is to pass the value,
That is to say, when passing a parameter, only the parameter value is passed into the function.
The other is address transmission. when passing a parameter, the address function a (var B: integer): integer of the parameter is input;
When calling function a, a (I); in fact, the parameter is @ I.
To understand the following explanation process, you need to take a look at how to understand the const source and var dest in the move parameter.
Address:
Http://www.cnpack.org/showdetail.php? Id = 476
(A typical context ?)
In the Pascal Implementation of the function, source refers to the input address and returns the result again,
Therefore, it still indicates the source before it is passed in. To obtain the address passed in the Assembly, use @ source.
That is to say, this var encapsulates and hides the address fetch operation passed in when the function is called and the operation specified once in the function body.
For example:
Procedure (I: integer );
VaR
J: integer;
Begin
J: = I;
End;
During the call, the I value is passed in and assigned to J. This is understandable.
However, if:
Procedure (var I: integer );
VaR
J: integer;
Begin
J: = I;
End;
In the underlying implementation, that is, in assembly, the I address is passed in,
Then the function refers to it once internally, obtains its value, and assigns a value to J.
However, the functions of J: = I; remain unchanged.
However, if I: = 0 is written in the function body, the implementation functions of these two functions are different.
Without var, the input is an I value, which exists in a temporary place, possibly a register or a stack zone.
I: = 0; it is to set the value of this temporary place to 0.
The address with VAR passed in is the I address, and this address value also has a temporary location.
However, when the value is assigned, the address is directed to the I before the input, and I: = 0 changes the value of the variable before the input.
Iii. test instances
According to the above introduction, I tested the machine. Learning is learning and learning.
// Debugging environment: XP SP2 + DELPHI6 + update2
// Debug settings: Disable the optimization option.
// Mainly look at the efficiency
// How should we apply the statements in actual programming and avoid confusion in parameter declarations.
// For the moment, process names A, B, and C are called a mode, B mode, and C mode.
// Note: The following is only an analysis of Integer Parameters.
Procedure A (I: integer );
VaR
J: integer;
Begin
J: = I;
I: = 11;
End;
Procedure B (var I: integer );
VaR
J: integer;
Begin
J: = I;
I: = 12; // because of VaR type I replication, you do not need to disable the optimization Option
End;
Procedure C (const I: integer );
VaR
J: integer;
Begin
J: = I;
// I: = 12; // cocould not compile
End;
Procedure tform1.btntestvarclick (Sender: tobject );
VaR
KA: integer;
KB: integer;
KC: integer;
Begin
KA: = 11;
KB: = 12;
KC: = 13;
A (KA );
B (Kb );
C (KC );
Log ('ka '+ inttostr (KA ));
Log ('kb' + inttostr (Kb ));
Log ('kc '+ inttostr (KC ));
End;
// Delphi local variable generation features:
// The address direction in the stack for storing ka, kb, and KC is from high address to low address
0047d084 c745f80b000000 mov [EBP-$08], $ 0000000b
0047d08b c745f40c000000 mov [EBP-$ 0C], $ 0000000c
0047d092 c745f00d000000 mov [EBP-$10], $ 0000000d
0047d099 8b45f8 mov eax, [EBP-$08]
0047d09c e86fffffff call
0047d0a1 8d45f4 Lea eax, [EBP-$ 0C] // B var get the address
0047d0a4 e883ffffff call B
0047d0a9 8b45f0 mov eax, [EBP-$10]
0047d0ac e89bffffff call C
0047d0b1 8d55e4 Lea edX, [EBP-$ 1C]
Procedure A (I: integer );
00472855 push EBP
0047cd29 8bec mov EBP, ESP
0047cd2b 83c4f8 add ESP,-$08
0047cd2e 8945fc mov [EBP-$04], eax // open a space in the stack to store the parameter I value
0047cd31 8b45fc mov eax, [EBP-$04]
0047348945f8 mov [EBP-$08], eax
0047cd37 c745fc0b000000 mov [EBP-$04], $ 0000000b
0047cd3e 59 pop ECx
0047cd3f 59 pop ECx
004740-5d pop EBP
0047cd41 C3 RET
Procedure B (var I: integer );
00474455 push EBP
0047458bec mov EBP, ESP
0047cd47 83c4f8 add ESP,-$08
0047cd4a 8945fc mov [EBP-$04], eax // open up a space in the stack to store the input address
0047cd4d 8b45fc mov eax, [EBP-$04]
0047cd50 8b00 mov eax, [eax] // One More addressing
0047cd52 8945f8 mov [EBP-$08], eax
0047cd55 8b45fc mov eax, [EBP-$04] // One More addressing
0047cd58 c7000c000000 mov [eax], $ 0000000c
0047cd5e 59 pop ECx
0047cd5f 59 pop ECx
0047cd60 5d pop EBP
0047cd61 C3 RET
Procedure C (const I: integer );
0047cd64 55 push EBP
0047cd65 8bec mov EBP, ESP
0047cd67 83c4f8 add ESP,-$08
0047cd6a 8945fc mov [EBP-$04], eax // open up a space in the stack to store the parameter I value
0047cd6d 8b45fc mov eax, [EBP-$04]
0047cd70 8945f8 mov [EBP-$08], eax
0047cd73 59 pop ECx
0047cd74 59 pop ECx
0047cd75 5d pop EBP
0047cd76 C3 RET
Description:
// For Integer Parameters,
The Execution code efficiency of A and C is relatively high,
A is concise. C will increase the time for the compiler to process Const.
The internal execution process of A and C is no different except Const.
B is used to modify external variables within the function.
How to use it? I want to see how sysutils. PAS and strutils handle it.
I took a look at sysutils and strutils,
In sysutils,
For most function parameters, if they are basic types, such as integer and byte, they basically follow the mode.
If the parameters are strings, they are all constant declarations in the B mode (no const is used ).
For example:
Function strtoint (const S: string): integer;
Function strtointdef (const S: string; default: integer): integer;
Function trystrtoint (const S: string; out value: integer): Boolean;
Function inttostr (value: integer): string; overload;
Function inttostr (value: int64): string; overload;
Function trimleft (const S: string): string; overload;
Function trimleft (const S: widestring): widestring; overload;
Some special cases:
Procedure scantonumber (const S: string; var pos: integer );
Function scanchar (const S: string; var pos: integer; Ch: Char): Boolean;
Function strlcat (DEST: pchar; const Source: pchar; maxlen: Cardinal): pchar;
Function strcomp (const str1, str2: pchar): integer;
In strutils,
Function reversestring (const atext: string): string;
Function leftstr (const atext: string; const acount: integer): string;
Function rightstr (const atext: string; const acount: integer): string;
Function midstr (const atext: string; const astart, acount: integer): string;
In system. Pas
Procedure _ wstrdelete (var s: widestring; index, Count: integer );
Function strpos (const str1, str2: pchar): pchar; assembler;
Function strupper (STR: pchar): pchar; assembler;
Function strlower (STR: pchar): pchar; extends er;
Function strpas (const STR: pchar): string;
Personal Summary of the form of parameter Declaration
I believe that the use of function parameters in system, sysutils, and strutils in Delphi is useful.
Standing on the shoulders of giants, in actual development, the principle of declaring the parameters of most common functions is:
If it is in string format, you must add the const and use the C mode.
If it is a basic type such as integer, the mode is used and nothing is added.
If special requirements such as transfer memory and string deletion are taken into account, use the VaR statement.
There are still many unsolved or unproven problems:
1. Why is it best to declare string as const?
2. The role of const and so on.
Postscript:
Afterwards, I read the process and functions in Chapter 6 of Pascal essentials, and I think some of them need to be listed for reference:
1,
The passing parameter of the Pascal routine can be a value parameter or a reference parameter.
Value parameter passing is the default parameter passing method: the copy of the value parameter is pushed into the stack. The routine uses and operates the copy value in the stack, not the original value.
When passing parameters through reference, the parameter values are not copied to the pressure stack in the normal way (avoiding copying value to the pressure stack usually speeds up program execution ),
Instead, you can directly reference the original parameter value. The code in the routine also accesses the original value, so that the parameter value can be changed in the process or function.
2,
Parameter reference technology is available in most programming languages. Although it is not in C language, it is introduced in C ++.
In C ++, the symbol "&" is used to indicate the reference. In VB, parameters without byval are referenced.
3,
Passing parameters by reference makes sense to the ordered type, Traditional string type, and large record type.
In fact, Delphi always transmits objects through values, because the Delphi object itself is a reference.
Therefore, passing an object through a reference is meaningless (except in special cases), because it is equivalent to passing a reference to another reference.
The case of Delphi long string is slightly different. long string looks like a reference, but if you change the string variable of this string,
The string will be copied Before update.
The long string passed as a value parameter is referenced only in terms of memory usage and operation speed,
However, if you change the value of the string, the initial value will not be affected.
On the contrary, if a long string is passed by reference, the initial value of the string can be changed.