Insider Discussion of String Type in Object Pascal

zhaozj2021-02-11  213

In Object Pascal, String is a variable length string that converts it to a character pointer type compatible with the Windows API. In fact, the String type is a pointer, you can read it with SizeOf, regardless of the actual length of the string, Sizeof (Astring) is always 4. The String is different from the general null-terminal character pointer. String also retains additional part of the space for recording information such as string length and reference count. The exact format of the String type in memory is as follows:

(4 bytes) Assign size (4 bytes) Reference count (4 bytes) string length (unordered length) Characters (1 bytes) $ 0 End Character

To verify this, we can add a String variable for private to private, and dynamically change its length and content in the program, while observing what changes in its allocation and length. In addition, in order to observe the change of the reference count, only when two strings are copied to each other, we can implement this in the program.

Please create a new Application, place an Edit on the form, a listbox and three button. Where EDIT is used to change the contents of the string; Listbox is used to record tracking information; three buttons are used to observe the current status of the string, and observe the reference counting of the string and the clear list content.

Add a variable in the Form's statement:

Type

TFORM1 = Class (TFORM)

...

Private

String;

END;

Event processing of adding three buttons is as follows:

Procedure TFORM1.BUTTON1CLICK (Sender: TOBJECT);

VAR

PSZ: PCHAR;

PDW: PDWORD;

DW1, DW2, DW3: DWORD;

Begin

s: = edit1.text;

PSZ: = PCHAR (S);

PDW: = PDWORD (PSZ);

DEC (PDW); DEC (PDW); DEC (PDW);

DW1: = PDW ^;

Inc (PDW); DW2: = PDW ^;

Inc (PDW); DW3: = PDW ^;

Listbox1.items.add (Format ('[current] size:% d, ref:% D, LEN:% D',

[DW1, DW2, DW3]));

END;

Procedure TFORM1.BUTTON2CLICK (Sender: TOBJECT);

VAR

PSZ: PCHAR;

PDW: PDWORD;

DW1, DW2, DW3: DWORD;

S2: STRING;

P1, P2: POINTER;

Begin

s: = edit1.text;

PSZ: = PCHAR (S);

PDW: = PDWORD (PSZ);

DEC (PDW); DEC (PDW); DEC (PDW);

DW1: = PDW ^;

Inc (PDW); DW2: = PDW ^;

Inc (PDW); DW3: = PDW ^;

Listbox1.items.add (Format ('[Before Assign] size:% D, REF:% D, LEN:% D',

[DW1, DW2, DW3]));

S2: = S;

P1: = POINTER (PCHAR (S));

P2: = POINTER (PCHAR (S2)); showMessage (Format ('p1 =% p, p2 =% P', [P1, P2]));

PSZ: = PCHAR (S);

PDW: = PDWORD (PSZ);

DEC (PDW); DEC (PDW); DEC (PDW);

DW1: = PDW ^;

Inc (PDW); DW2: = PDW ^;

Inc (PDW); DW3: = PDW ^;

Listbox1.items.add (Format ('[after assign] size:% D, REF:% D, LEN:% D',

[DW1, DW2, DW3]));

S2: = S2 'another string';

P1: = POINTER (PCHAR (S));

P2: = POINTER (PCHAR (S2));

ShowMessage (Format ('p1 =% p, p2 =% p', [p1, p2]));

PSZ: = PCHAR (S);

PDW: = PDWORD (PSZ);

DEC (PDW); DEC (PDW); DEC (PDW);

DW1: = PDW ^;

Inc (PDW); DW2: = PDW ^;

Inc (PDW); DW3: = PDW ^;

Listbox1.items.add (Format ('[AFTER COW] Size:% D, REF:% D, LEN:% D',

[DW1, DW2, DW3]));

END;

Procedure TFORM1.BUTTON3CLICK (Sender: TOBJECT);

Begin

Listbox1.Items.clear;

END;

If you are more clear about the concept of pointers, the above code is not difficult to understand. Below is the output of the program:

[CURRENT] SIZE: 22, REF: 5, LEN: 5

[Before Assign] Size: 22, REF: 2, LEN: 5

[After assign] Size: 22, REF: 3, LEN: 5

[After COW] Size: 22, Ref: 2, LEN: 5

Observe the above results, you can draw a few conclusions:

1. There is a fixed quantity relationship between "allocated size" and "string length", that is, allocated size = string length 17. Why have this relationship? Please look at the memory distribution of String type: (4-byte) Assign size (4 bytes) Reference count (4 bytes) string length (unordered length) Characters (1 bytes) $ 0 End characters, 4 4 4 (Strlen) 1, should be 13 (strlen), that is, there should be 4 bytes of space, and its use is unclear. It is worth mentioning that if you can't empty the string, then the result of Len may not be the 0 you think, but a number that makes you eat.

2. Since allocation size and string length are represented by 4 bytes, and the String type is dynamically allocated, the maximum possible length of the string should be 2 ^ 32-17 bytes.

3. At the time of copying the string, Object Pascal is not a simple copy of the string, but the method of reference count, pointing two strings to the same memory space, and reference count plus 1. When the string variable is cleared, the reference count is reduced by 1, and if the reference count has been reduced to 0, the string can be truly cleared. Obviously, this method is higher than the efficiency of replication the entire string. 4. When assigning a string to the string, Object Pascal first checks whether the reference count count of the string is 1. If so, according to the general method, it can be assigned directly; otherwise, there are two or more strings to point to the same address, which is more complicated. Object Pascal uses a Copy-ON-WRITE mechanism (COW) to open up a buffer for the current string, copy the new content; at the same time, the original string reference count is minus one.

5. Know the String memory layout, we also know the meaning of Pchar (Str). However, when using PCHAR, the String dynamic growth and the function of the reference count are lost, so be careful, pay attention to the calculation of the PCHAR length and the string length must be synchronized, otherwise it will be issued. For example, the code below does not work properly:

VAR

Str: string;

Begin

SETLENGTH (STR, 256);

GetWindowdirectory (Pchar (STR), 256);

Str: = STR '/WIN.INI';

END;

This result is incorrect. The reason is not correct because SETLENGTH sets the string length to 256, and the length of PCHAR calculates only to the first $ 0. The correct way should be:

SETLENGTH (STR, 256);

GetWindowsDirectory (Pchar (STR), 256);

SETLENGTH (STR, STRLEN (Pchar (STR)));

Str: = SETR '/WIN.INI';

Description: The above program is passed under Delphi 5. Borland does not guarantee that the String's memory structure remains unchanged in the later Delphi version, so the above example is only used as a test, and the actual program should not be used in this way, so illustrates it.

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

New Post(0)