将char分配给字符串时如何解决W1047/W1068警告?

Mik*_*nni 3 delphi string char compiler-warnings delphi-xe7

我有一个简单的函数,可以将数字转换为字符串(类似于Excel列号1..n可以转换为列名的方式A-ZZZ).由于我经常使用它,我已经删除了局部变量作为速度优化,并且只能Result直接使用.

当我编译时,我得到这两个警告:

W1047不安全代码'var param的字符串索引'

W1068将来可能不支持修改字符串

这是缩短的功能:

function Idx2Code_(Idx: integer): string;
begin
  SetLength(Result, 3); // init Result size
  if Idx <= 26 then
  begin
    // single char: A-Z
    Result := Chr(64 + Idx);
    SetLength(Result, 1);
  end
  else if Idx <= 676 then
  begin
    // 2 chars codes: BA-ZZ
    Result[1] := Chr((Idx div 26) + 64 + 1); // <- warnings for this line
    Result[2] := Chr((Idx mod 26) + 64);     // <- warnings for this line
    SetLength(Result, 2);
  end
  else
  begin
    // 3 chars codes: BAA-ZZZ
    Result[1] := Chr((Idx div 676) + 64 + 1);            // <- warnings for this line
    Result[2] := Chr(((Idx mod 676) div 26) + 64 + 26);  // <- warnings for this line
    Result[3] := Chr((Idx mod 26) + 64 + 26);            // <- warnings for this line
  end;
end;
Run Code Online (Sandbox Code Playgroud)

我可以使用局部变量,但它较慢,我不想要.

我不想在将来的Delphi版本中使用可能变得"过时"的代码.

如何解决警告,但尽可能保持简单性和速度?

Rem*_*eau 5

在移动开发中,默认情况下,Delphi string类型的直接索引是基于0的(可以使用该{$ZEROBASEDSTRINGS OFF}指令禁用).

在桌面开发中,默认情况下,直接索引仍然是基于1的,但将来可能会从 0开始.

由于平台之间存在这种差异string,因此不鼓励直接编制索引,从而发出警告消息.为避免这种情况,TStringHelper.Chars[]所有平台都提供基于0的属性.但是,这个属性是只读的,所以你不能用它来修改一个内容string(在某一点上,Embarcadero正在考虑制作string不可变的,但后来决定反对它,但警告仍然存在).

在这种情况下,您将不得不:

  1. 禁用警告,并使用适合平台的索引.您可以用它Low(string)来帮助您:

    {$WARN UNSAFE_CODE OFF}
    {$WARN IMMUTABLE_STRINGS OFF}
    function Idx2Code_(Idx: integer): string;
    begin
      if Idx <= 26 then
      begin
        // single char: A-Z
        SetLength(Result, 1);
        Result[Low(string)] := Chr(64 + Idx);
      end
      else if Idx <= 676 then
      begin
        // 2 chars codes: BA-ZZ
        SetLength(Result, 2);
        Result[Low(string)] := Chr((Idx div 26) + 64 + 1);
        Result[Low(string)+1] := Chr((Idx mod 26) + 64);
      end
      else
      begin
        // 3 chars codes: BAA-ZZZ
        SetLength(Result, 3);
        Result[Low(string)] := Chr((Idx div 676) + 64 + 1);
        Result[Low(string)+1] := Chr(((Idx mod 676) div 26) + 64 + 26);
        Result[Low(string)+2] := Chr((Idx mod 26) + 64 + 26);
      end;
    end;
    {$WARN IMMUTABLE_STRINGS DEFAULT}
    {$WARN UNSAFE_CODE DEFAULT}
    
    Run Code Online (Sandbox Code Playgroud)
  2. 用一个TStringBuilder:

    uses
      System.SysUtils;
    
    function Idx2Code_(Idx: integer): string;
    var
      SB: TStringBuilder;
    begin
      SB := TStringBuilder.Create(3);
      try
        if Idx <= 26 then
        begin
          // single char: A-Z
          SB.Append(Chr(64 + Idx));
        end
        else if Idx <= 676 then
        begin
          // 2 chars codes: BA-ZZ
          SB.Append(Chr((Idx div 26) + 64 + 1));
          SB.Append(Chr((Idx mod 26) + 64));
        end
        else
        begin
          // 3 chars codes: BAA-ZZZ
          SB.Append(Chr((Idx div 676) + 64 + 1));
          SB.Append(Chr(((Idx mod 676) div 26) + 64 + 26));
          SB.Append(Chr((Idx mod 26) + 64 + 26));
        end;
        Result := SB.ToString;
      finally
        SB.Free;
      end;
    end;
    
    Run Code Online (Sandbox Code Playgroud)

    或者,TStringbuilder它有自己的Chars[]可写属性:

    uses
      System.SysUtils;
    
    function Idx2Code_(Idx: integer): string;
    var
      SB: TStringBuilder;
    begin
      SB := TStringBuilder.Create(3);
      try
        if Idx <= 26 then
        begin
          // single char: A-Z
          SB.Length := 1;
          SB[0] := Chr(64 + Idx);
        end
        else if Idx <= 676 then
        begin
          // 2 chars codes: BA-ZZ
          SB.Length := 2;
          SB[0] := Chr((Idx div 26) + 64 + 1);
          SB[1] := Chr((Idx mod 26) + 64);
        end
        else
        begin
          // 3 chars codes: BAA-ZZZ
          SB.Length := 3;
          SB[0] := Chr((Idx div 676) + 64 + 1);
          SB[1] := Chr(((Idx mod 676) div 26) + 64 + 26);
          SB[2] := Chr((Idx mod 26) + 64 + 26);
        end;
        Result := SB.ToString;
      finally
        SB.Free;
      end;
    end;
    
    Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅Embarcadero的文档:

从桌面迁移Delphi代码到移动:使用基于0的字符串

  • 为什么不简单地`结果:= Chr(...)+ Chr(...)+ Chr(...)`? (2认同)