【问题标题】:Warning: Unsafe typecast of 'TSmallPoint' to 'Integer'警告:'TSmallPoint' 到 'Integer' 的不安全类型转换
【发布时间】:2012-12-28 22:47:42
【问题描述】:

我在我的项目中使用此代码:

var
  P: TPoint;

MyControl.Perform(WM_LBUTTONDOWN, 0, Longint(PointToSmallPoint(P)));

编译器给了我一个警告:

[Warning]: Unsafe typecast of 'TSmallPoint' to 'Integer'

但是,在Controls.pas 中使用了相同的代码没有任何警告 - 例如在TControl.BeginDrag 方法中:

....
Perform(WM_LBUTTONUP, 0, Longint(PointToSmallPoint(P)));

我在Controls.pas 单元中看不到任何{$warnings off}

为什么编译器会警告我,但会跳过Controls.pas 的警告?
这段代码不安全吗?


编辑:在我的项目选项 -> 编译器消息 -> 不安全类型转换已选中(默认情况下未选中)。
也许这就是@David 和@Ken 无法重现警告的原因。

【问题讨论】:

  • 我无法重现该警告。您能否提供一个完整的程序来演示该警告。
  • 我也无法复制它,使用以下命令:procedure TForm3.FormCreate(Sender: TObject); var P: TPoint; begin P := Mouse.CursorPos; Perform(WM_LBUTTONDOWN, 0, Longint(PointToSmallPoint(P))); end;
  • IIRC,这个警​​告是在 Delphi 7 中新添加的,因为预期 Delphi .NET,这样的转换不起作用。不是您问题的答案,但除非您打算使用它,否则您不必担心警告。
  • 您的编辑是正确的;我没有选中unsafe type cast,因为它不再适用。 (当他们为 .NET 开发 Delphi 时,为了与 .net 兼容而在 Delphi 6 或 7 中添加了它,以便更轻松地编写适用于 .NET 和 Win32 的代码;由于 .NET 产品的 Delphi 已停产,因此该警告(以及上面的两个)不再适用)。
  • 我添加了一个答案,解释了为什么会为未来的读者生成警告(以及为什么禁用它是安全的)。

标签: delphi delphi-7


【解决方案1】:

这是因为您在 Project->Options->Compiler Messages 中检查了unsafe typecast 警告。取消选中是安全的(就像上面的 unsafe typeunsafe code 一样。(见下文。)

我无法重现警告,因为我未检查不安全的类型转换。它不再适用。 (当他们为 .NET 开发 Delphi 时,为了与 .net 兼容而在 Delphi 6 或 7 中添加了它,以便更轻松地编写适用于 .NET 和 Win32 的代码;由于 .NET 产品的 Delphi 已停产,因此该警告(以及上面的两个)不再适用)。这三个警告中的“不安全”使用 .NET 的“不安全”含义,意思是“非托管”。

来自 Delphi 7 帮助文件(搜索“Compiler Changes”)(强调我的):

Delphi dcc32 编译器现在支持三个额外的编译器警告:Unsafe_Type、Unsafe_Code 和 Unsafe_Cast。 默认情况下禁用这些警告,但可以使用编译器指令 {$WARN UNSAFE_CODE ON}、编译器命令行开关 (dcc32 -W+UNSAFE_CODE) 以及在 IDE 中的项目上启用|选项|编译器消息页面。

此功能旨在帮助您将代码移植到 Microsoft .NET 平台的托管执行环境。在托管执行环境中,“不安全”是指在即时 (JIT) 编译器执行的静态分析期间无法验证操作。此类代码可能会带来安全风险,因为没有足够的信息用于JIT 编译器验证其运行时行为。不安全代码的示例包括指针操作和内存覆盖。

【讨论】:

  • @David:我不知道;我没有检查。可能有一个与.NET 相关的{$IFDEF},但我在解释为​​什么发帖人会收到警告(以及为什么你和我无法重现它)。我会看一下,但这里确实不相关,因为它没有生成警告。
  • 控制单元方面似乎是问题的核心。
  • 这是 .net 特定且不再适用的信息来源。将一对 smallints 转换为 longint 对我来说似乎很不安全
  • 你回答了那部分。我回答了主题暗示的问题,即“为什么在控制单元不生成时会生成此警告”;我解释了为什么会出现警告,如何修复它,以及为什么通过关闭警告来修复它是安全的。快速浏览一下 D7 的 Controls.pas 并没有显示 {$IFDEF},因此它可能根本没有被编译,而 Vlad 只是查看了 Controls 并看到了它;我不知道他是否真的编译了 Controls 或者只是它没有生成警告,并且并不认为它是相关的。弗拉德显然同意了。
  • 该警告(以及其他两个“不安全”警告)的文档,以及添加警告时 Borland/CodeGear 新闻组中的帖子。添加它们专门是为了进行 Win32/.NET 兼容的单源项目,在这种情况下,“不安全”的含义就是该词的 .NET 框架含义。
【解决方案2】:

如果您自己编译 Controls 单元并启用不安全类型转换警告,那么您将看到警告。但是,如果您链​​接预构建的 .dcu 文件,则不会看到任何警告。编译器只对它编译的单元发出警告。

作为一般规则,RTL 和 VCL 单元会生成大量提示和警告。如果我必须重新编译它们,我总是必须关闭这些单元上的提示和警告。


现代documentation 警告说:

您使用了静态代码分析无法证明它不会覆盖内存的数据类型或操作。例如,您可能已将 (sic) 一条记录转换为另一条记录,或者将一个实例转换为另一条记录。

并且该警告确实适用于您的代码。您的代码不安全。编译器无法验证将两个 16 位整数叠加到一个 32 位整数上是否正确。所以编译器会警告你。代码是否正确由您决定。

现在,该警告似乎主要针对 .net 编译器。尽管如此,它仍然对 Win32 编译器有意义。将一条记录叠加在另一条记录上是可疑行为。

【讨论】:

  • +1。您确实回答了“为什么编译器会警告我,但跳过 Controls.pas 的警告”的问题。但是肯关于“不再适用的不安全类型转换”的回答让我明白了。所以也许我应该得到-1。
  • 我以为是这个问题。
  • Ken 确实回答了“此代码不安全吗?”。并解释了有关“不安全类型转换”的主题。
  • 这个问题特别指的是 D7,我提供了 D7 文档中完全冲突的信息(并引用了它的位置)。您的文档链接专门指的是 XE3,这并不相同。
  • Delphi XE3 Vcl.Controls 单元(TControl.BeginDrag 在大约第 6940 行,如 Vlad 的问题中所引用)仍然具有他引用的完全相同的代码行;显然,在处理此消息时,类型转换是合适的。
猜你喜欢
  • 2012-04-07
  • 1970-01-01
  • 2021-03-27
  • 2015-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多