如何解决将char分配给string时的W1047/W1068警告?
How to solve W1047/W1068 warnings when assigning char to string?
我有一个将数字转换为字符串的简单函数(类似于 Excel 列号 1..n
可以转换为列名 A-ZZZ
的方式)。由于我经常使用它,我已经删除了局部变量作为速度优化并且只直接使用 Result
。
当我编译时,我收到了这 2 个警告:
W1047 Unsafe code 'String index to var param'
W1068 Modifying strings in place may not be supported in the future
这是缩短的函数:
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;
我可以使用局部变量,但速度较慢,这是我不想要的。
我不想使用在未来的 Delphi 版本中可能会变成 "obsolete" 的代码。
如何解决警告,同时尽可能保持简单和快速?
在移动开发中,Delphi的string
类型的直接索引默认是0-based(这可以通过{$ZEROBASEDSTRINGS OFF}
指令)。
在桌面开发中,直接索引默认情况下仍然是1-based,但可能将来会变成0-based。
由于平台之间的这种差异,string
的直接索引不鼓励向前发展,因此警告消息。为避免这种情况,所有平台都提供基于 0 的 TStringHelper.Chars[]
属性。然而,这个 属性 是 只读的,所以你不能用它来修改 string
的内容(有一次,Embarcadero 正在考虑制作 string
不可变的,但后来决定反对,但警告仍然存在)。
在这种情况下,您必须:
禁用警告,并使用适合平台的索引。您可以使用 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}
使用 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;
或者,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;
有关详细信息,请参阅 Embarcadero 的文档:
Migrating Delphi Code to Mobile from Desktop: Use 0-Based Strings
我有一个将数字转换为字符串的简单函数(类似于 Excel 列号 1..n
可以转换为列名 A-ZZZ
的方式)。由于我经常使用它,我已经删除了局部变量作为速度优化并且只直接使用 Result
。
当我编译时,我收到了这 2 个警告:
W1047 Unsafe code 'String index to var param'
W1068 Modifying strings in place may not be supported in the future
这是缩短的函数:
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;
我可以使用局部变量,但速度较慢,这是我不想要的。
我不想使用在未来的 Delphi 版本中可能会变成 "obsolete" 的代码。
如何解决警告,同时尽可能保持简单和快速?
在移动开发中,Delphi的string
类型的直接索引默认是0-based(这可以通过{$ZEROBASEDSTRINGS OFF}
指令)。
在桌面开发中,直接索引默认情况下仍然是1-based,但可能将来会变成0-based。
由于平台之间的这种差异,string
的直接索引不鼓励向前发展,因此警告消息。为避免这种情况,所有平台都提供基于 0 的 TStringHelper.Chars[]
属性。然而,这个 属性 是 只读的,所以你不能用它来修改 string
的内容(有一次,Embarcadero 正在考虑制作 string
不可变的,但后来决定反对,但警告仍然存在)。
在这种情况下,您必须:
禁用警告,并使用适合平台的索引。您可以使用
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}
使用
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;
或者,
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;
有关详细信息,请参阅 Embarcadero 的文档:
Migrating Delphi Code to Mobile from Desktop: Use 0-Based Strings