|
PChar |
Top Previous Next |
|
Pretranslated C# code > Pointers > PChar `PChar` simulates Delphi `PChar` and, in the Unicode runtime, `PWideChar`.
public struct PChar : IPointer<char>
It is a UTF-16 character pointer built on `Pointer<char>`. Arithmetic and indexed access are measured in UTF-16 code units.
`PChar` is intended for translated code that uses functions such as `StrLen`, `StrCopy`, `StrPCopy`, `StrAlloc`, `StrDispose`, `FormatBuf`, or direct null-terminated character traversal.
Value semantics
`PChar` is a struct. Copying a `PChar` copies its current position while sharing the backing buffer:
PChar p = new PChar(buffer); PChar q = p + 1;
`p` and `q` have independent positions but observe the same character data.
Null pointers
Use `default` for Delphi `nil`:
PChar p = default;
Test with:
if (p.IsNull()) { }
Dereferencing a null `PChar` throws `NullReferenceException`.
Writable string copy
Constructing `PChar` from `string` creates a writable, null-terminated `char[]` copy:
PChar p = new PChar("Hello"); p[0] = 'h';
This does not modify the original C# string because `System.String` is immutable.
The copied content can be converted back explicitly:
string changed = p.ToString();
or, for legacy generated code:
p.Synchronize(ref text);
Synchronization is an explicit copy operation. It is not automatic.
Read-only non-copying string view
When only reading is required, use:
PChar p = PChar.FromStringView(text);
This creates a non-copying UTF-16 view of the C# string. The view includes a logical trailing null character. Any write through this pointer throws `InvalidOperationException`.
Character-array backing
char[] buffer = { 'H', 'e', 'l', 'l', 'o', '\0' };
PChar p = new PChar(buffer);
By default, this is a non-copying view. Writes through `p` directly modify `buffer`.
The constructor does not append a terminator to an existing `char[]`. Code that treats the array as a null-terminated string must provide sufficient storage and a terminating `\0`.
Use `copy: true` when an independent array copy is required:
PChar copy = new PChar(buffer, 0, copy: true);
Allocated buffers
PChar managed = new PChar(characterCount); PChar native = new PChar(characterCount, alloc: true);
The managed form uses a zero-initialized `char[]`. The native form allocates owned native storage of `characterCount * sizeof(char)` bytes.
Release owned native storage with:
DelphiMemory.FreeMem(ref native);
`Dispose()` or `SetNull()` only clears the current pointer value.
Dereferencing and indexed access
char c = p.Deref(); p.Assign('A');
char next = p[1]; p[1] = 'B';
These correspond to:
C := P^; P^ := 'A'; C := P[1]; P[1] := 'B';
Pointer arithmetic
p++; p--; p = p + 4; p = p - 2;
Each step advances by one UTF-16 code unit. Internally, one character step normally advances by two bytes.
Changing the dereferenced character
The compatibility helpers:
p.DerefAdd(value); p.DerefSubstract(value);
support translated code such as:
Inc(P^, Value); Dec(P^, Value);
Length and capacity
`Length` scans from the current position to the first null character, or to the end of the current view if no terminator is present.
`Capacity` reports the number of character slots available from the current position. It is not the same as the null-terminated string length.
Writing strings
p.Assign("Text");
writes the characters followed by `\0` into the existing backing.
The pointer never automatically resizes its backing. If the view does not contain enough writable character slots, an exception is thrown.
The same rule applies to `Insert`.
Conversion to managed values
string text = p.ToString(); char[] chars = p.ToCharArray(); string part = p.Substring(from, count);
`ToString()` and `ToCharArray()` start at the current pointer position and stop before the first null character. `ToCharArray()` does not include the terminator.
Writable C# string buffers
For a native-style operation that must modify a C# string, use `Utf16StringBuffer`:
using Utf16StringBuffer buffer = new Utf16StringBuffer(text, capacity);
PChar p = buffer.Pointer;
// Pointer operations modify the buffer.
text = buffer.Commit();
`Commit()` creates the resulting immutable C# string from the buffer. This is the preferred replacement for old implicit `PChar` synchronization patterns.
Native API interoperability
`ToIntPtr()` returns the current address. Managed backing is pinned.
For scoped calls, prefer:
using PointerPin pin = p.Pin(); NativeFunction(pin.Address);
There is no separate native mirror that must be copied back with `FromIntPtr()`. Managed and native views already refer to their actual shared backing. `PChar.FromIntPtr()` is therefore only a compatibility no-op in the current runtime.
Memory cleanup
`PChar` implements `IDisposable` because it implements `IPointer<char>`, but `Dispose()` only clears that pointer value. It does not free a shared allocation.
For memory allocated by `StrAlloc`, `GetMem`, or the native `PChar` constructor, use the appropriate runtime free operation, normally:
DelphiMemory.FreeMem(ref p);
Typical translated code
Delphi:
P := PChar(S); while P^ <> #0 do Inc(P);
C# with a read-only view:
PChar p = PChar.FromStringView(s);
while (p.Deref() != '\0') { p++; }
Delphi:
P[0] := 'A';
C#:
p[0] = 'A';
Limitations
`PChar` is not a native pointer to a C# string.
Important differences are:
Use `Pointer`, `UntypedPointer`, or `Pointer<T>` for binary buffers and record data.
|
|
This page belongs to the Delphi2C# Documentation |
Delphi2C# home Content |