将Delphi代码移植到64位——为什么没有编译器警告?

9
我们有一个大型的Delphi XE代码库,我们想要将其移植到64位平台上。
我拥有Delphi XE2许可证,但我找不到任何警告或提示,可以帮助我检测在64位平台下可能导致数据丢失的有效32位结构。例如,在32位编译器中完全有效的THandle到Cardinal赋值,在编译Win64时不会引发任何警告。
当使用Delphi 2009进行Unicode迁移时,我们有大量警告,这些警告帮助我们跟踪和修复可疑的代码。但是在XE2中,我找不到任何东西。我无法想象没有集成在编译器级别上的任何内容来避免我们手动审查所有代码。
我错过了什么吗?如果您尝试过,那么您是如何将项目移植到64位的?
谢谢!

THandle 不再映射到 integer,而是映射到 NativeUInt(在 Win32 下只是一个 cardinal)。这可能有助于识别问题。 - Arnaud Bouchez
我似乎在XE(1)中也无法获得这种消息,例如将int分配给byte... - GolezTrol
1
@GolezTrol:你说得对,但在我看来,当分配任务可能导致在Win32或Win64上编译时产生不同结果时,应引入一种新的编译器警告类别。 - Adrien Reboisson
3个回答

2

你没有错过任何东西。产品中没有任何帮助你的内容。

我也觉得有点失望,但我完全相信Emba的设计师考虑过这个问题。我只能得出结论,他们的经验是添加这样的警告会产生更多噪音而不是信号。例如,Delphi编译器从未在将不兼容的整数类型赋值时发出警告。例如,将整数赋值给字节从未被视为警告或错误。

现在是时候启动grep并搜索Integer(.*), Longint(.*), Cardinal(.*), Longword(.*), THandle等。


为了回应Arnaud的评论和回答,我提供以下代码,当目标为64位时可以编译且没有警告和错误。

procedure NaughtyCode;
var
  Handle: THandle;
  int: Integer;
  card: Cardinal;
  P: Pointer;
begin
  Handle := high(Handle);
  int := Handle;
  card := Handle;
  P := Pointer(Handle);
  int := Integer(P);
  card := Cardinal(P);
end;

我不明白为什么他们没有包含任何可选的警告来简化这个过程...类型转换是一回事,但正如我所说,在Win64下具有不同大小的数据类型之间进行赋值(例如THandle)要难得多,并且可能导致数据丢失/数据损坏。我真的不理解他们的选择。 - Adrien Reboisson
使用grep进行搜索是可以的,但每个人都应该意识到不要将其用于整个“替换”选项 - 这可能会破坏代码。在所有情况下,在Win64下编译时,THandlepointerinteger()类型转换将引发显式编译器错误。因此,在我的看法中,搜索并非强制性的:当将目标平台设置为Win64时,编译器会有意为您完成它。 - Arnaud Bouchez
@Arnaud 我一定做错了什么。你如何配置XE2以便对我在问题中添加的代码进行警告或错误提示? - David Heffernan
我支持你,David。编译这样的代码时我没有得到任何错误。 - Adrien Reboisson
显式类型转换意味着“我知道我在这里做什么”。您要求编译器停止假设强制转换意味着有意的操作。有一些关于String到AnsiString的IMPLICIT强制转换的警告,但是很少有关于EXPLICIT类型转换,因为EXPLICIT类型转换是解决问题的方法。现在,如果明确的向下转换甚至是可选的警告,那么如何编写“清洁代码”?如果Embarcadero听取了您的建议,整个编译器将变得更慢,更占用空间,而这真正应该是一个独立的工具,如果需要的话。我建议您向Peganza PAL的作者请求添加您想要的功能。 - Warren P
1
同意显式类型转换。但是对于我所谓的“跨平台的非可移植赋值”,涉及类型的大小取决于目标平台,该怎么办? - Adrien Reboisson

0
大约5年前,我将它们移植到64位Free Pascal。(即使只是部分,并使用简单的单元测试来检测)使用两种编译器进行测试可以发现更多问题。

1
谢谢...不过我觉得有点令人沮丧,因为你不得不使用两个编译器来规避你以显著价格购买的官方编译器的限制! - Adrien Reboisson
据我所知,dcc64.exe是“官方”的64位Delphi编译器,如果您想编译Delphi代码。 - Adrien Reboisson
1
David Heffernan:我的应用程序做到了。但是我可以通过创建DPR并导入一些单元来轻松编译大部分内容。对于警告而言,这已经足够了。Delphi<>FPC兼容性的情况并不像您描述的那么糟糕。听起来您曾尝试过使用它,但预期效果类似于一次盲目的编译,让您感到失望。它肯定不是完全免费的,但这并不意味着它是不可能或无用的。只有当您在每个单元中都使用了类似Datasnap之类的东西时,它才会变得相当令人绝望。 - Marco van de Voort
现在,我非常想知道的是,FPC编译器具体如何帮助进行64位移植。它检测到了你代码中哪些问题?警告有多可配置?虽然我无法立即处理整个应用程序,但你所描述的可能有助于部分解决。 - David Heffernan
没有什么特别的。主要是做了XE2用户正在做的一切(删除不需要的汇编代码,修复int<>pointer组件标签、头记录对齐问题等)。唯一的区别是我有一个工作的内部汇编器 :-) 至于一般的故障排查,首先是不同的内存布局,因为所有东西虽然兼容,但实现方式不同。如果你有Heisenbug,很可能在FPC上的行为略有不同。此外,它还有一个随机化本地变量选项(用于查找未初始化的变量),并且FPC二进制文件可以与valgrind分析器/调试器一起使用。 - Marco van de Voort
显示剩余15条评论

0

正如您所述,大多数潜在问题来自于:

  • WinAPI更改(但大多数情况下是相同/兼容的);
  • THandle不再映射到integer,而是映射到NativeUInt(即,在Win32下仅为cardinal);
  • 在指针算术中,Integer类型转换未映射到NativeInt

最后一个将引发编译器错误,而不仅仅是警告(这是明确的类型不匹配),THandle的更改应该被警告。

我对Embarcadero的主编译器不会那么苛刻 - 我更关心背景编译器(例如CodeInsight)是否与主编译器同步。对我来说,主编译器工作得很好,我从来没有抱怨过缺少的警告。只需明确搜索THandle并不那么困难。


请查看我的更新问题。据我所知,您在这个答案中陈述的事实是不正确的。我不会点踩,因为我尊重您总是准确无误的事实,并且很可能是我简单地忽略了某些事情。那么,请问我忽略了什么? - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接