2011-01-03 8 views
15

w C/C++ zawsze maszCzy są jakieś różnice między tablicą a spakowaną tablicą w Delphi?

SizeOf(array[N] of T) = N * SizeOf(T); 

w Pascalu/Delphi można użyć „tablicę suchy”, aby mieć pewność, że powyższe assert jest prawdą, ale robi „pakowane” specifier mieć dowolną wartość praktyczną dla tablic w Delphi? Nie mogę utworzyć przykład „niespakowanego” macierzy, macierze wydaje zawsze „pakowane”:

type 
    A = array[0..2] of Byte; 
    B = array[0..99] of A; 
    C = packed record 
    C1, C2, C3: Byte; 
    end; 
    D = array[0..99] of C; 

procedure TForm10.Button1Click(Sender: TObject); 
begin 
    Assert(SizeOf(A) = 3); 
    Assert(SizeOf(B) = 300); 
    Assert(SizeOf(D) = 300); 
end; 

(C/C++ struktury i zapisy Delphi są różne - mogą być „rozpakowaniu” tak, że wielkość Struktura jest większa niż suma wymiarów pól ze względu na wyrównanie pól.)

+0

Zgaduję, że bez modyfikatora 'upakowanego 'przyszłe wersje kompilatora delphi mogą korzystać z macierzy niezbyt kompaktowych. Osobiście używam 'packed 'wtedy i tylko wtedy, gdy zależy mi na dokładnym układzie pamięci. – CodesInChaos

Odpowiedz

26

Nie ma praktycznego wpływu na Delphi. Jedynym typem, jaki może w rozsądny sposób wpłynąć, jest typ o najdziwniejszym połączeniu i rozmiarze, Extended, który ma rozmiar 10 i wyrównanie równe 8. Jednak tablice o numerach Extended są zasadniczo zapakowane (chociaż nadal mają wyrównanie 8). jeśli dyrektywa packed działała tak, jak w przypadku rekordów, miałyby wyrównanie 1).

Dlaczego mówię, że tablice o numerze Extended to jedyny typ, na jaki może wpływać? Nie ma innego typu Delphi, wbudowanego lub który można komponować, który ma rozmiar, który nie jest całkowitą wielokrotnością jego wyrównania (pozostawiając na boku starsze wersje Delphi i kilka błędów). Wyrównanie jest tym, co sprawia, że ​​rekordy są większe dzięki dopełnieniu; powoduje, że pola są rozstawione tak, że każde pole zaczyna się od przesunięcia, które jest wielokrotnością całkowitą jego wyrównania. W analogicznym przypadku z tablicami występuje tylko jeden typ, a jeśli rozmiar jest już wielokrotnością wyrównania typu, nie ma potrzeby wypełniania.

Oto program, który pokazuje, w jaki sposób Extended wpływa na rozmiar i wyrównanie w zależności od tego, czy jest zapakowany w rekord, czy nie; można dodać packed do tablic i zobacz, że nie ma różnicy:

type 
    TWrap = record 
    X: Extended; 
    end; // field size=10, align=8, => actual size=16 

    TArr1 = array[1..3] of TWrap; // 3*16 => size=48, align=8 
    TArr2 = array[1..3] of Extended; // 3 * 10 => size=30, align=8 

    TRec1 = record 
    A: Byte; 
    B: TArr1; 
    end; 

    TRec2 = record 
    A: Byte; 
    B: TArr2; 
    end; 

var 
    x: TRec1; 
    y: TRec2; 
begin 
    Writeln('Size of TArr1: ', SizeOf(TArr1)); 
    Writeln('Alignment of TArr1: ', Integer(@x.B) - Integer(@x.A)); 
    Writeln('Size of TArr2: ', SizeOf(TArr2)); 
    Writeln('Alignment of TArr2: ', Integer(@y.B) - Integer(@y.A)); 
end. 

Więcej słów o wyrównanie i packed: packed ma inny efekt (na zapisy), a nie tylko gwarantuje, że nie ma wyściółka dodania: to również oznacza rekord jako sam w sobie wyrównanie 1. Ma to negatywny wpływ na to, że często jest niewyrównany, gdy jest używany gdzie indziej. Do celów zapewnienia zgodności operacyjnej języka/OS, tylko w przypadku, gdy inny język nie stosuje reguł wyrównania OS (zwykle oznaczających reguły wyrównania C) w przypadku użycia dyrektywy pakowania. (Niektóre nagłówki Windows API mają niepoprawne wyrównanie dla typów zdefiniowanych w nich, pamiętajcie, i musieliście z tym żyć od tego czasu). Z drugiej strony, pakowanie może być uzasadnione, ale istnieją wiele innych problemów także w odniesieniu do wyboru typu (np. liczba całkowita to 2 bajty w 16-bitowym Delphi, ale 4 bajty później).

Delphi próbuje użyć reguł kompatybilnych z C do wyrównania. W przeszłości występowały tutaj pewne błędy (szczególnie w przypadku rekordów takich jak TRec = rekord A, B: Extended end, versus TRec = record A: Extended, B: Extended end;), ale te błędy powinny teraz zostać naprawione

+0

Bardzo interesujące, dziękuję. Mam nadzieję, że Extended przetrwa w 64-bitowym kompilatorze i nie będzie miało aliasów do podwójnego. – kludg

+0

To wstyd, że spakowane implikujące wyrównanie = 1 dla rekordów nie jest udokumentowane. Przynajmniej nie był to ostatni raz kiedy patrzyłem, kiedy natrafiłem na problem! –

0

Delphi XE Pomoc mówi to dla dynamicznych tablic

Dynamiczny układ pamięci array (tylko Win32):

offsetowy Zawartość

-8 32-bit = reference-count 
-4 32-bit = length indicator (number of elements) 
0..Length * (size of element) -1 = array elements 

Więc przez ten dok jest pakowany.