在 Delphi 64 位下 const 参数和类型转换会像以前一样工作吗?
作为一般规则,我在使用指针时通过利用 Const(无类型)参数而不是硬编码类型来规避许多经典设计陷阱。这使我在执行高级图形函数时获得了速度优势,同时将技术细节留给了编译器。它还使得在 Delphi 和 Free Pascal 中使用相同的代码变得很容易,只需进行最小的更改。然而,最近,由于 Embarcadero 对 Delphi 的演变及其即将推出的安全模型的 vauge 声明,我开始对此提出质疑。
例如,考虑以下示例:
Type TSomeDataProc = procedure (const aInput;var aOutput) of Object;
(* Convert 8-bit pixel to 16-bit pixel *)
Procedure TMyClass.ProcessSomeData08x565(Const aInput;var aOutput);
var r,g,b: Byte;
Begin
FPalette.ExportTriplets(Byte(aInput),r,g,b);
Word(aOutput):=(R SHR 3) SHL 11 or (G SHR 2) SHL 5 or (B SHR 3);
End;
(* Convert 16-bit pixel to 24-bit pixel *)
Procedure TMyClass.ProcessSomeData565x888(Const aInput;var aOutput);
Begin
With TRGBTriple(aOutput) do
Begin
rgbtRed:=(((word(aInput) and $F800) shr 11) shl 3);
rgbtGreen:= (((word(aInput) and $07E0) shr 5) shl 2);
rgbtBlue:= ((word(aInput) and $001f) shl 3);
end;
End;
我们现在有两个具有相同声明的过程,但它们处理像素数据的方式非常不同。这给我们带来了使用查找表来获得正确的“转换器”方法的好处。这应该在构造函数中或在分配图片位图的任何地方完成,如下所示:
Private
FLookup: Array[pf8bit..pf32bit,pf8bit..pf32bit] of TSomeDataProc;
Procedure TMyClass.Create;
Begin
Inherited;
FLookup[pf8bit,pf16bit]:=ProcessSomeData08x565;
FLookup[pf16bit,pf24Bit]:=ProcessSomeData565x888;
end;
每当我们需要转换像素时,我们只需查找正确的方法并使用它即可。所有过程的语法保持相同 - 因此我们不必担心每个过程“如何”运行。就我们班而言,他们看起来都一样。
Procedure TMyClass.ConvertTo(aFormat:TpixelFormat);
Begin
// Get function for the correct pixel converter
FConvertProc:=FLookup[CurrentFormat,aFormat];
//Use the pixel converter
FConvertProc(GetSourcePixelAddr(x,y),GetTargetPixelAddr(x,y));
end;
问题是:这种类型转换(例如:Const 到 Byte 或任何定义的 Record 类型)能够在 64 位下生存吗?我个人不明白为什么不,但是 Embarcadero 对于新的“安全”模型和指针使用有点模糊,所以我发现将来保护我的代码有点困难。
As a general rule I have circumvented a lot of classical design traps when using pointers by taking advantage of Const (untyped) parameters rather than hard coded types. This gives me the benefit of speed when executing advanced graphical functions while leaving the technical details up to the compiler. It has also made it easy to use the same code in Delphi and Free Pascal with minimal changes.Lately however, I have begun to question this due to Embarcadero's vauge statements on the evolution of Delphi and it's upcomming safety model.
For instance, concider the following example:
Type TSomeDataProc = procedure (const aInput;var aOutput) of Object;
(* Convert 8-bit pixel to 16-bit pixel *)
Procedure TMyClass.ProcessSomeData08x565(Const aInput;var aOutput);
var r,g,b: Byte;
Begin
FPalette.ExportTriplets(Byte(aInput),r,g,b);
Word(aOutput):=(R SHR 3) SHL 11 or (G SHR 2) SHL 5 or (B SHR 3);
End;
(* Convert 16-bit pixel to 24-bit pixel *)
Procedure TMyClass.ProcessSomeData565x888(Const aInput;var aOutput);
Begin
With TRGBTriple(aOutput) do
Begin
rgbtRed:=(((word(aInput) and $F800) shr 11) shl 3);
rgbtGreen:= (((word(aInput) and $07E0) shr 5) shl 2);
rgbtBlue:= ((word(aInput) and $001f) shl 3);
end;
End;
We now have two procedures with identical declarations, but they handle the pixeldata very differently. This gives us the benefit of using a lookup table to get the correct "converter" method. This should be done in either the constructor or wherever the picture bitmap is allocated, like this:
Private
FLookup: Array[pf8bit..pf32bit,pf8bit..pf32bit] of TSomeDataProc;
Procedure TMyClass.Create;
Begin
Inherited;
FLookup[pf8bit,pf16bit]:=ProcessSomeData08x565;
FLookup[pf16bit,pf24Bit]:=ProcessSomeData565x888;
end;
Whenever we need to convert pixels we simply look up the correct method and use it. The syntax remains the same for all the procedures - so we dont have to worry about "how" each procedure operates. As far as our class is concerned, they all look the same.
Procedure TMyClass.ConvertTo(aFormat:TpixelFormat);
Begin
// Get function for the correct pixel converter
FConvertProc:=FLookup[CurrentFormat,aFormat];
//Use the pixel converter
FConvertProc(GetSourcePixelAddr(x,y),GetTargetPixelAddr(x,y));
end;
The question is: Will this kind of typecasting (e.g: Const to Byte or any defined Record type) survive under 64bit? I personally cant see why not, but Embarcadero have been sort of vague regarding the new "safety" model and pointer-use, so I find it a bit hard to safeguard my code for the future.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
由于 RTL 中使用了此类技巧,因此我认为在不破坏大量代码的情况下,我不会认为弃用 var 或 const 无类型参数。
Embarcadero 尽力保持尽可能多的向后兼容性。
在首先发出有关使用外部汇编器的通知之后,他们甚至应该在 64 位编译器中重新包含内联汇编。
而且这样的修改与 64 位模型没有任何关系,而 x86-64 汇编器是需要编写的新代码。
所以你应该将这个问题发布到Embarcadero官方新闻组,但我认为你不必担心这一点。
Since such tricks are used in the RTL, I don't see deprecating a var or const typeless parameter without a lot of code breaking.
Embarcadero tries its best to maintain as much backward compatibility as possible.
They even should include back the inline asm in the 64 bit compiler, after having first made some notification about the use of an external assembler.
And such a modification won't have anything to do with the 64 bit model, whereas the x86-64 assembler was a new piece of code to write.
So you should post this question of the official Embarcadero newsgroup, but I think you don't have to worry about this.
请注意,FPC 已经更改了 CONST 参数,但在本例中并未更改。
对于正常情况,对于所有调用约定,CONST 不再由引用保证,而是遵循相应 ABI 指定的内容。新的参数类型 CONSTREF 保证通过引用。
与所有兼容性破坏一样,TP/Delphi 中的 CONST 始终是引用的问题,但 TP/Delphi 也始终是 x86。
除此之外,所有 STDCALL 函数都会发生变化,例如 IUnknown.Queryinterface:
http:// wiki.freepascal.org/User_Changes_Trunk#IInterface.QueryInterface.2C_._AddRef_and_._Release_definitions_have_been_changed
原因或多或少是因为在这些情况下,x86 ABI 信息进入了通用接口,这是不跨架构兼容的。因此,我们必须猜测它是该语言的一部分,还是该语言的 x86 实现的一部分。
请注意,IUnknown 也用在其他平台上,例如 Firefox 的 XPCOM
Delphi 也可能会遇到此类障碍,但我认为它们主要会影响具有显式调用约定要求的函数/方法,因为人们可以更改内部约定以满足需要,但一实际上无法改变世界的其他部分((XP)COM 或现有的 C(++) 库)以适应 Delphi 中的现有代码
Note that FPC already did change the CONST parameter, though not in this case.
For the normal case, CONST is not guaranteed by reference anymore for all calling conventions, but follows whatever the respective ABI specifies. A new parameter type, CONSTREF is guaranteed to be by reference.
Like all breakage of compatibility it is the problem that in TP/Delphi CONST is always by ref, but TP/Delphi is also always x86.
Among others all STDCALL functions change, like e.g. IUnknown.Queryinterface:
http://wiki.freepascal.org/User_Changes_Trunk#IInterface.QueryInterface.2C_._AddRef_and_._Release_definitions_have_been_changed
The reason is more or less that in these cases, x86 ABI information entered the generic interface, something which is not cross-architecture compatible. So one has to guess if it is part of the language, or part of the x86 implementation of the language.
Note that IUnknown is also used on other platforms for e.g. Firefox' XPCOM
Delphi might also hit such snags, but I think they primarily will effect functions/methods with explicit calling convention requirements, because one can change the internal convention to suit needs, but one can't practically change the rest of the world ((XP)COM or existing C(++) libraries) to suit existing code in Delphi