【问题标题】:How to convert a null terminated string to string?如何将空终止的字符串转换为字符串?
【发布时间】:2015-08-22 22:45:06
【问题描述】:

我想将一些数据记录存储到磁盘。我想让每条数据记录的大小相等,这样我就可以快速计算并跳转到某个记录。 因此,我将记录中唯一的字符串存储为一个字符数组:

type TFileNameIO = array[1..512] of Char;

从磁盘读取字符串后,我的字符串内容是这样的:

c:\windows#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0 等

我想截断 #0 字符,我做了这样的事情:

function GetFileName(DiskName: TFileNameIO): string;
VAR PC: PChar;
begin
 SetString(Result, PChar(@DiskName), Length(DiskName));     <----- here Result is: c:\windows#0#0#0 etc
 PC:= PChar(Result);
 Result:= WideCharToString(PC);
end;

有更好的方法吗?

【问题讨论】:

  • 我用Delphi已经有一段时间了,但我认为你可以做 PC = @Result[1] ; WideCharToString(PC);

标签: delphi delphi-xe7


【解决方案1】:

您可以将空终止的PChar 直接分配给String

function GetFileName(DiskName: TFileNameIO): string;
begin
 Result := PChar(@DiskName);
end;

只需确保TDiskName 始终包含一个空终止符。如果它可以完全包含没有 null 的字符,您将不得不这样做:

function GetFileName(DiskName: TFileNameIO): string;
var
 Len, I: Integer;
begin
  Len := 0;
  For I := Low(DiskName) to High(DiskName) do
  begin
    if DiskName[I] = #0 then Break;
    Inc(Len);
  end;
  SetString(Result, PChar(@DiskName), Len);
end;

【讨论】:

  • 我得到:“E2010 不兼容的类型:'string' 和 'Pointer'”
  • 我一直忘记 Delphi 的 @ 运算符通常不输入,因为默认情况下 {$TYPEDADDRESS} 是关闭的。
  • 如果我添加 {$TYPEDADDRESS on} 其他代码会被破坏。我可能需要检查整个代码以修复使用 @ 的地方。
  • 在这种情况下需要@,但您必须确保将PChar 分配给string,因此要么使用{$TYPEDADDRESS ON}@DiskName[1],要么使用带有PChar(@DiskName) 的显式类型转换。
【解决方案2】:

您的函数不是必需的,因为您可以简单地将字符数组分配给字符串变量。

type
  TCharArray = array [1..512] of Char;
....
var
  arr: TCharArray;
  str: string;
....
arr := ...;
str := arr;

这导致str 被分配arr 的内容。编译器通过调用System._UStrFromWArray 来实现这一点,它首先寻找一个空终止符。如果找到一个,则确定str 的长度。否则,将复制数组的全部内容,并Length(str)=Length(arr)

作为更广泛的观点,我建议您改为使用从零开始的字符数组。来自documentation

从零开始的字符数组与 PChar 和 PWideChar 兼容。当您使用字符数组代替指针值时,编译器会将数组转换为指针常量,其值对应于数组第一个元素的地址。

这使您可以更轻松地与需要 PChar 参数的函数进行互操作。

顺便说一句,按值传递TFileNameIO 效率低下,因为它涉及内存副本。通过引用传递此类类型。例如作为const 参数。

【讨论】:

  • 我从来没有使用从 1 开始的字符数组作为从 0 开始的字符。我希望写TCharArray = array [0..511] of Chararray [1..512] 在实践中有效吗? +1
  • @Arnaud 谢谢。基于 1 的数组支持从字符数组到字符串的赋值。但它与 PChar 不兼容。你可以从我的编辑中看出第一部分对我来说也是一个惊喜。除了基于零的数组,我个人不会考虑其他任何东西。
  • 我以为不会为 DiskName 制作副本。据我了解(stackoverflow.com/questions/9543472/…),仅当我触摸(写入/修改)DiskName 时才会创建副本。
  • 这不适用。在 Q 的代码中,您按值传递一个固定长度的数组。因此,制作了一份副本并通过了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-25
  • 1970-01-01
  • 2020-10-15
  • 1970-01-01
  • 2019-05-09
  • 2012-12-23
相关资源
最近更新 更多