11

德尔福有:

var: 通过引用传递;参数既是输入又是输出。
out: 通过引用传递;参数仅输出。
const:路过.....好吧,这取决于;参数只是输入。
in通过引用传递;参数仅输入,不会更改没有“在”。

我不介意没有勺子,但我想念in;考虑以下代码,是否有更清洁的方法?

type TFastDiv = record 
strict private
  FBuffer: Int64;
  other fields
....

//Must be `var` because `const` would pass a Int64 by value
//                      |||
//                      VVV
function DivideFixedI32(var Buffer: Int64; x: integer): integer;
asm  
  mov  r9,rcx                   
  imul dword ptr[rcx]    // do stuff with the buffer
  ..
  mov     ecx, [r9+4]    // do other stuff with the rest of the buffer  

{将代码更改为imul ecx;...;shr r9,32;mov ecx,r9d允许按值传递,但我们假设不得更改代码。}

class operator TFastDiv.IntDivide(x:integer; const buffer:TFastDiv):integer;
begin
  Result:= DivideFixedI32(Int64((@buffer.FBuffer)^), abs(x)); <<-- Ugly
  if (x < 0) then Result:= - Result;
end;

DivideFixed永远不会改变缓冲区。该例程的重点是这buffer是一个不会改变的预先计算的值。

在类运算符中,我将缓冲区声明为 const,因为记录不得更改。

问题是:
如果我坚持将buffer参数声明IntDivide为 asconst是否有更简洁的编码方式,或者我是否陷入了 pointer_to/points_to hack?

4

2 回答 2

15

较新的编译器版本(从 XE3 开始)支持[Ref]装饰器:

procedure Foo(const [Ref] Arg1: Integer; [Ref] const Arg2: Byte);

示例改编自文档,强调[Ref]可以在const关键字之前或之后。

于 2013-09-30T14:39:33.747 回答
6

如果要确保通过引用,唯一的选择(Delphi XE3 之前)是传递一些大的东西。
即大于 sizeof(pointer)

type TFastDiv = record 
strict private
  FBuffer: Int64;   <<-- make sure this is the first member
  other fields
....

function DivideFixedI32(const Buffer: TFastDiv; x: integer): integer;
...
class operator TFastDiv.IntDivide(x:integer; const buffer:TFastDiv):integer;
begin
  Result:= DivideFixedI32(buffer, abs(x));

Delphi 帮助文件中的这一行:

1、2 或 4 字节的集合、记录和静态数组作为 8 位、16 位和 32 位值传递。较大的集合、记录和静态数组作为指向该值的 32 位指针传递。此规则的一个例外是,记录总是在 cdecl、stdcall 和 safecall 约定下直接在堆栈上传递;以这种方式传递的记录的大小向上舍入到最近的双字边界。

具有误导性,应改为/阅读为:

直到 SizeOf(pointer) 的集合、记录和静态数组作为 8 位、16 位和 32 位值(x64 上的 64 位值)传递。大于 SizeOf(Pointer) 的集合、记录和静态数组作为指向值的指针传递。此规则的一个例外是,记录总是在 cdecl、stdcall 和 safecall 约定下直接在堆栈上传递;以这种方式传递的记录的大小向上舍入到最近的 SizeOf(pointer) 边界。

于 2013-09-30T13:33:53.910 回答