2011-01-03 23 views
15

In C/C++ di avere sempreC'è qualche differenza tra array e array confezionato in Delphi?

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

in Pascal/Delphi si può usare 'array compresso' per essere sicuri che quanto sopra affermare che è vero, ma lo fa specificatore 'confezionato' avere alcun valore pratico per gli array in Delphi? Non riesco a creare un esempio di allineamento 'spacchettato', gli array sembra sempre 'confezionate':

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; 

(I/C++ strutture C e le registrazioni Delphi sono diversi - possono essere 'spacchettato' in modo che la dimensione della struttura è maggiore della somma delle dimensioni dei campi a causa dell'allineamento dei campi.)

+0

Immagino che senza il modificatore 'packed' le future versioni del compilatore delphi possano utilizzare matrici non compatte. Personalmente uso 'imballato' se e solo se mi interessa l'esatto layout di memoria. – CodesInChaos

risposta

26

Non ha alcun effetto pratico in Delphi. L'unico tipo che potrebbe ragionevolmente influenzare è il tipo con l'allineamento e la combinazione di dimensioni più strane, Extended, che ha una dimensione di 10 e un allineamento di 8. Tuttavia, gli array di Extended sono già compressi (sebbene abbiano ancora un allineamento di 8 ; se la direttiva packed funzionava come nei record, avrebbe un allineamento di 1).

Perché dico che gli array di Extended sono l'unico tipo che potrebbe influenzare? Non esiste un altro tipo di Delphi, integrato o che tu possa comporre, che ha una dimensione che non è un multiplo intero del suo allineamento (a parte vecchie versioni di Delphi e alcuni bug). L'allineamento è la cosa che rende i record più grandi con il padding; fa sì che i campi siano distanziati in modo che ogni campo inizi con un offset che è un multiplo intero dell'allineamento del suo tipo. Nel caso analogo con gli array, è coinvolto un solo tipo e se la dimensione è già un multiplo dell'allineamento del tipo, non è necessario eseguire il padding.

Ecco un programma che mostra come Extended influisce sulla dimensione e sull'allineamento a seconda che sia racchiuso o meno in un record; è possibile aggiungere packed agli array, e vedere non fa alcuna differenza:

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. 

Più parole su allineamento e packed: packed ha un altro effetto (il record) piuttosto che solo garantendo che non v'è alcuna imbottitura aggiunto: è anche segna il record come se avesse un allineamento di 1. Ciò ha l'effetto negativo di causarne il disallineamento frequente quando viene utilizzato altrove. Ai fini dell'interoperabilità linguistica/OS, solo nel caso in cui l'altra lingua non stia utilizzando le regole di allineamento del sistema operativo (che di norma indicano le regole di allineamento C) dovrebbe essere utilizzata la direttiva imballata. (Alcune intestazioni dell'API di Windows hanno un allineamento errato per tipi definiti all'interno di esse, si badi, e hanno dovuto convivere con esso da allora.) Per motivi di compatibilità con un formato di file, d'altra parte, imballato può essere giustificato, ma ci sono ci sono anche molte altre preoccupazioni riguardo alla scelta del tipo (ad esempio, l'intero era 2 byte in Delphi a 16 bit, ma successivamente 4 byte).

Delphi tenta di utilizzare le regole compatibili con C per l'allineamento. In passato aveva alcuni bug (in particolare con record come TRec = record A, B: Esteso, contro TRec = record A: Esteso; B: Esteso;), ma questi bug dovrebbero essere corretti ora

+0

Molto interessante, grazie. Spero che Extended sopravviverà nel compilatore a 64 bit e non sarà sottoposto ad aliasing da raddoppiare. – kludg

+0

È un vero peccato che l'imballaggio implicante l'allineamento = 1 per i record non sia documentato. Almeno non era l'ultima volta che guardavo, quando ho trovato il problema! –

0

Delphi XE Aiuto dice che questo per gli array dinamici

dinamica layout di memoria array (solo Win32):

Offset Contenuto

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

Così, da quel documento viene compresso.

Problemi correlati