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?
答案 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(指针)边界。