【问题标题】:Variable might not have been initialized. Can I switch this warning on for a string?变量可能尚未初始化。我可以为字符串打开此警告吗?
【发布时间】:2011-08-11 20:46:40
【问题描述】:

当我编译这段代码时

{$WARNINGS ON}
function Test(s: string): string;
var
  t: string;
  d: double;
begin
  if s = '' then begin
    t := 'abc';
    d := 1;
  end;

  Result := t + FloatToStr(d);
end;

我收到警告“变量 'd' 可能尚未初始化”,但我没有收到关于变量 't' 的相同警告。这似乎不一致。此代码只是显示编译器警告的一个简单示例,但我刚刚在我的实时代码中发现了一个错误,该错误可能会被未初始化字符串变量的编译时警告捕获。我可以在 Delphi 6 中以某种方式打开此警告吗?还是在较新版本的 Delphi 中?

【问题讨论】:

  • 我非常怀疑现在的代码是否会编译。您在“t:= 'abc'”之前缺少一个“开始”。
  • 糟糕,错字已更正:) 我将其输入 SO 而不是复制和粘贴。
  • @soid ...如果变量 s 不是空字符串,那么您将遇到该代码的问题,因为 FloatToString(d) 可能会爆炸 - 就像警告所说的 d 可能尚未初始化。您可能会在其他地方给它一个值,但鉴于发布的内容,我会将“d := 1”移到“开始”之后。或者,我会在开始之后放置“d := 0”,然后在 if 语句中将其设置为 1(如果需要的话)。在您清除所有警告之前,您的代码是不完整的。
  • @TDelphiHobbyist 您是否阅读了问题和代码?!!
  • @TDelphiHobbyist:问题的重点在于简单类型会收到警告,但字符串不会。作为人为示例的示例代码如果以保证d被初始化的方式编写将毫无意义!

标签: delphi compiler-warnings initialization


【解决方案1】:

不,这里没有开关。警告不会发生,因为字符串是编译器管理的类型,并且总是由编译器初始化。

【讨论】:

  • 谢谢。这就是我所担心的。
  • 你为什么要担心它总是被初始化的事实?
  • 如果您未能初始化作为函数结果变量的托管类型,是否有人知道您是否会收到这样的警告?
  • @David:你没有收到这样的警告。例如:function StringResult: string; begin beep; end; 编译时没有提示或警告。 (D2009)
  • @David:由于字符串是托管类型,因此函数 Result 被初始化为该类型的空托管实例。见this answer by Barry Kelley
【解决方案2】:

是的:-)

使用 shortstrings 或 pChars

{$WARNINGS ON}
function Test: String;
var
  p: pChar;
  d: double;
begin
  Result := p + FloatToStr(d);
end;
//This code will give a warning.

说真的

不,正常的 Delphi 字符串和短字符串会自动初始化为 ''(空字符串)。短字符串存在于堆栈中,不需要清理。其他字符串是所谓的“托管”类型,当它们不再使用引用计数时会自动删除。

PChars,好消息
pChars 只是指针。 Delphi管理它们。
然而,Delphi确实自动将它们转换为字符串,反之亦然。

pChars 坏消息
如果您将 pChar 转换为字符串,Delphi 会将 pChar 的内容复制到字符串中,而您仍然负责销毁 pChar。
另请注意,这种复制需要时间,如果你这样做很多会减慢你的代码。

如果你将 字符串转换为 pChar,Delphi 会给你一个指向字符串所在地址的指针。而且!! Delphi 将停止管理字符串。您仍然可以为字符串赋值,但它不会再自动增长。

发件人:http://www.marcocantu.com/epascal/English/ch07str.htm

以下代码将无法按预期工作:

procedure TForm1.Button2Click(Sender: TObject);
var
  S1: String;
begin
  SetLength (S1, 100);
  GetWindowText (Handle, PChar (S1), Length (S1));
  S1 := S1 + ' is the title'; // this won't work
  Button1.Caption := S1;
end;

这个程序可以编译,但是当你运行它时,你会大吃一惊:按钮的 Caption 将有窗口标题的原始文本,没有你添加到它的常量字符串的文本。问题是当 Windows 写入字符串时(在GetWindowText API 调用中),它没有正确设置长 Pascal 字符串的长度。 Delphi 仍然可以使用该字符串进行输出,并且可以通过查找空终止符来确定它何时结束,但是如果您在空终止符之后附加更多字符,它们将被完全跳过。

我们如何解决这个问题?解决方案是告诉系统将GetWindowText API 调用返回的字符串转换回Pascal 字符串。但是,如果您编写以下代码:

S1 := String (S1);

系统将忽略它,因为将数据类型转换回自身是无用的操作。要获得正确的长 Pascal 字符串,您需要将字符串重新转换为 PChar 并让 Delphi 将其再次正确转换回字符串:

S1 := String (PChar (S1));

实际上,您可以跳过字符串转换,因为在 Delphi 中 PChar 到字符串的转换是自动的。这是最终代码:

procedure TForm1.Button3Click(Sender: TObject);
var
  S1: String;
begin
  SetLength (S1, 100);
  GetWindowText (Handle, PChar (S1), Length (S1));
  S1 := String (PChar (S1));
  S1 := S1 + ' is the title';
  Button3.Caption := S1;
end;

另一种方法是使用 PChar 字符串的长度来重置 Delphi 字符串的长度,方法是:

SetLength (S1, StrLen (PChar (S1)));

【讨论】:

  • 为什么是 -1,这显然是在开玩笑,它确实说明了没有警告的原因以及哪些字符串会发出警告。
  • 你好约翰,我没有对你投反对票。我猜有人认为短字符串是一种可能会引入问题的类型,因为它的长度限制为 255 个字符,所以最好完全忘记它。实际上,在我的情况下,您的代码会阻止我发现的错误,因为我在字符串中使用的字符不超过 255 个。
  • @soid:如果您认为可能的话,您可以暂时将所有出现的string 替换为ShortString,然后编译并观察警告。这样,您可能无需事先初始化就可以找到所有使用字符串的地方。
  • @Andriy M:我刚刚尝试过,但在 Delphi 6 中,shortstring 似乎没有给我警告。我需要更新版本的 Delphi,还是我做错了什么?这实际上似乎是一个相当不错的主意,因为我可以拥有自己的字符串类型,我可以偶尔出于警告目的从字符串切换到短字符串,或者我可以以某种方式干预内置的字符串类型。
  • @Everybody:Johan 是否误以为短字符串会产生警告?如果是这样,也许我可以创建一个具有所需属性的类型,例如 '+' 仅用于编译时警告目的?
猜你喜欢
  • 2016-07-07
  • 2012-01-02
  • 2015-03-22
  • 1970-01-01
  • 2012-03-25
  • 2015-07-04
相关资源
最近更新 更多