8

I understand that in Delphi, an empty string (AnsiString or WideString) can be represented by a nil pointer, or by a pointer to an actual empty string.

By experiment I've shown that in Delphi XE2 (with particular compiler settings) PChar('') <> nil. But is this guaranteed, or might it change in a future version, or be dependent on some compiler setting?

I'm having a crisis of confidence. If anyone can give me a definitive answer I'd be grateful.

Ian Goldby
  • 5,609
  • 1
  • 45
  • 81

1 Answers1

11

Yes. Type casts from string literals to PChar will never be null pointers. Type casts from strings of the same character type to PChar won't be null, either. (String to PChar, AnsiString to PAnsiChar, etc.)

Type casts of other things to PChar may be null, though. (Pointer to PChar, AnsiString to PWideChar, etc.)

The documentation covers this in the Mixing Delphi Strings and Null-Terminated Strings section of the String Types topic:

You can also cast a UnicodeString or AnsiString string as a null-terminated string. The following rules apply:

  • If S is a UnicodeString, PChar(S) casts S as a null-terminated string; it returns a pointer to the first character in S. Such casts are used for the Windows API. For example, if Str1 and Str2 are UnicodeString, you could call the Win32 API MessageBox function like this: MessageBox(0, PChar(Str1), PChar(Str2), MB_OK);. Use PAnsiChar(S) if S is an AnsiString.
  • You can also use Pointer(S) to cast a string to an untyped pointer. But if S is empty, the typecast returns nil.
  • PChar(S) always returns a pointer to a memory block; if S is empty, a pointer to #0 is returned.
  • When you cast a UnicodeString or AnsiString variable to a pointer, the pointer remains valid until the variable is assigned a new value or goes out of scope. If you cast any other string expression to a pointer, the pointer is valid only within the statement where the typecast is performed.
  • When you cast a UnicodeString or AnsiString expression to a pointer, the pointer should usually be considered read-only. You can safely use the pointer to modify the string only when all of the following conditions are satisfied:
    • The expression cast is a UnicodeString or AnsiString variable.
    • The string is not empty.
    • The string is unique - that is, has a reference count of one. To guarantee that the string is unique, call the SetLength, SetString, or UniqueString procedures.
    • The string has not been modified since the typecast was made.
    • The characters modified are all within the string. Be careful not to use an out-of-range index on the pointer.

The same rules apply when mixing WideString values with PWideChar values.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • Thanks. Would be be ungrateful of me to ask where this is documented? – Ian Goldby Feb 12 '13 at 15:57
  • 1
    @IanGoldby It's documented in the documentation. I just did a search. It's here: http://docwiki.embarcadero.com/RADStudio/XE3/en/String_Types#Mixing_Delphi_Strings_and_Null-Terminated_Strings Surely you could have done this too? ;-) – David Heffernan Feb 12 '13 at 16:00
  • @DavidHeffernan I looked under PChar. Thanks for the link. – Ian Goldby Feb 12 '13 at 16:04
  • 1
    @IanGoldby You have to hunt around a bit sometimes. I think the Delphi documentation is unfairly maligned. For sure it lacks in some areas, but who of us ever writes perfect documentation. By and large it's pretty good. Don't give up on it! – David Heffernan Feb 12 '13 at 16:05
  • Has it always been like that? I vaguely remember PChar(s) for empty strings returning `nil` sometimes. – CodesInChaos Feb 12 '13 at 16:06
  • @CodesInChaos Nope, it's always been like this. Otherwise Win32 interop would have been a nightmare. – David Heffernan Feb 12 '13 at 16:07