2013-09-30 11 views
9

Delphi posiada:mogę zmusić `const` przechodzić przez odniesienie (aka brakującej` in` parametru)

var: przechodzić przez odniesienie; parametr jest zarówno wejściowy, jak i wyjściowy.
out: przekazywać przez odniesienie; Parametr jest tylko wyjściowy.
const: przejść przez ..... to zależy; Parametr jest tylko wejściowy.
in: przekazywać przez odniesienie; parametr jest tylko wejściowy i nie zostanie zmieniony nie ma "w".

Nie mam nic przeciwko, że there is no spoon, ale brakuje mi in; biorąc pod uwagę poniższy kod, czy istnieje czystszy sposób robienia tego?

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 

{Zmiana kodu do imul ecx;...;shr r9,32;mov ecx,r9d pozwoliłoby podanie przez wartość, ale załóżmy, że kod nie musi być zmieniana.}

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 nigdy nie zmieni bufor. Cały punkt rutyny jest taki, że buffer jest wstępnie obliczoną wartością, która się nie zmienia.

W operatorze klasy deklaruję bufor jako const, ponieważ rekord nie może się zmienić.

Pytanie brzmi:
Gdybym domagać się deklarując parametr w IntDividebuffer jako const istnieje przejrzysty sposób kodowania albo ja utknął w pointer_to/points_to włamać?

+0

Co to jest "w"? Czego tak naprawdę brakuje: C++ 'const MyType & value' –

+0

' in' byłoby przeciwieństwem 'out', przekazywane przez referencję, ale gwarantowany parametr nie ulega zmianie; i tak, wskaźnik (aka pass_by_reference), który nie zostanie zmieniony wewnątrz procedury. – Johan

Odpowiedz

13

nowsze wersje kompilator (z XE3 r) wspiera [Ref] dekorator:

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

Przykład adaptacją the documentation, który podkreśla [Ref] może się albo przed albo po hasła const.

+3

+1 bardzo ładne. Czy wiesz, które kompilatory obsługują to? Czy kompilatory komputerów stacjonarnych to robią? –

+0

OK, mogłem to sprawdzić samodzielnie na kompilatorze XE5, a tam zaimplementowano [ref]. Oczekuję więc, że będzie on wszędzie wdrażany. –

+1

@DavidHeffernan XE3 wydaje się być pierwszym (po prostu wypróbowany) i tak, również kompilatorami na komputery stacjonarne. –

4

Jedyną opcją (pre Delphi XE3), jeśli chcesz zapewnić przekazywanie referencji, jest przekazanie czegoś dużego.
czyli większy niż sizeof (wskaźnik)

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)); 

Linia w Delphi help file:

Zestawy rejestry i statyczne tablice 1, 2 lub 4 bajtów są przekazywane jako 8-bitowej 16-bitowe i 32-bitowe wartości. Większe zbiory, rekordy i tablice statyczne są przekazywane do wartości wskaźników 32-bitowych. Wyjątkiem od tej reguły jest to, że rekordy są zawsze przekazywane bezpośrednio na stosie pod konwencjami cdecl, stdcall i safecall; rozmiar przekazywanego w ten sposób rekordu jest zaokrąglany w górę do najbliższej granicy dwóch słów.

jest mylące i powinno zostać zmienione/odczytywać jako:

Zestawy, rekordy i statyczne tablice aż do sizeof (wskaźnik) są przekazywane jako 8-bitowy, 16-bitowy, a 32-bitowe wartości (64-bitowe wartości na x64). Zestawy, rekordy i statyczne tablice większe niż SizeOf (Wskaźnik) są przekazywane jako wskaźniki do wartości. Wyjątkiem od tej reguły jest to, że rekordy są zawsze przekazywane bezpośrednio na stosie pod konwencjami cdecl, stdcall i safecall; rozmiar rekordu przekazywanego w ten sposób jest zaokrąglany w górę do najbliższej granicy SizeOf (wskaźnik).

Powiązane problemy