我可以强制`const`通过引用传递(也就是缺少的`in`参数)

时间:2013-09-30 12:32:00

标签: delphi pass-by-reference

德尔福有:

var:通过引用传递;参数是输入和输出 out:通过引用传递;参数仅输出。
const:通过.....这取决于它;参数仅输入。
in通过引用传递;参数仅为输入且不会更改没有“in”。

我不介意 there is no spoon ,但我想念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参数声明为const是否有更简洁的编码方式,或者我是否陷入了pointer_to / points_to hack?

2 个答案:

答案 0 :(得分:13)

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

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

改编自the documentation的示例,强调[Ref]可以在const关键字之前或之后进行。

答案 1 :(得分:6)

唯一的选择(在Delphi XE3之前),如果你想确保传递引用,就是传递大的东西。
即大于sizeof(指针)

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 help file中的这一行:

  

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

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

  
    

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