2011-01-03 6 views
15

En C/C++ que siempre tenga¿Hay alguna diferencia entre la matriz y la matriz empaquetada en Delphi?

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

En Pascal/Delphi se puede utilizar 'conjunto empaquetado' para asegurarse de que la aserción anterior es cierto, pero lo hace especificador 'lleno' tienen ningún valor práctico para las matrices de Delphi? No puedo crear un ejemplo de array 'desempaquetado', los arrays parece siempre 'empaquetados':

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; 

(Los/C++ estructuras C y registros de Delphi son diferentes - que puede ser 'desempaquetado' para que el tamaño de la estructura es mayor que la suma de los tamaños de los campos debido a la alineación de los campos.)

+0

Supongo que sin el modificador 'packed' futuras versiones del compilador delphi pueden usar matrices no compactas. Personalmente utilizo 'packed' si y solo si me importa el diseño de memoria exacto. – CodesInChaos

Respuesta

26

No tiene ningún efecto práctico en Delphi. El único tipo al que podría afectar razonablemente es el tipo con la combinación más extraña de alineación y tamaño, Extended, que tiene un tamaño de 10 y una alineación de 8. Sin embargo, las matrices de Extended están esencialmente empaquetadas (aunque todavía tienen una alineación de 8 ; si la directiva packed funcionara como lo hizo en los registros, tendrían una alineación de 1).

¿Por qué digo arreglos de Extended es el único tipo que podría afectar? No hay otro tipo de Delphi, integrado o que pueda componer, que tiene un tamaño que no es un múltiplo entero de su alineación (dejando de lado las versiones anteriores de Delphi y algunos errores). La alineación es lo que hace que los registros sean más grandes con relleno; hace que los campos se espacien para que cada campo comience en un desplazamiento que es un múltiplo entero de la alineación de su tipo. En el caso análogo con arreglos, solo hay un tipo involucrado, y si el tamaño ya es un múltiplo de la alineación del tipo, entonces no hay necesidad de relleno.

Aquí hay un programa que muestra cómo Extended afecta el tamaño y la alineación dependiendo de si está envuelto en un registro o no; puede agregar packed a las matrices, y ver que no hay diferencia:

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. 

Más palabras sobre la alineación y packed: packed tiene otro efecto (en registros) en lugar de sólo garantiza que no hay ningún relleno añadido: también marca que el registro tiene una alineación de 1. Esto tiene el efecto negativo de causar que se desalinee con frecuencia cuando se usa en otro lugar. A efectos de la interoperabilidad del lenguaje/sistema operativo, solo en el caso en que el otro idioma no esté utilizando las reglas de alineación del sistema operativo (que normalmente significan reglas de alineación C), debe usarse la directiva empaquetada. (Algunos encabezados de la API de Windows tienen una alineación incorrecta para los tipos definidos dentro de ellos, claro, y han tenido que vivir con eso desde entonces.) Por razones de compatibilidad con un formato de archivo, por otro lado, empaquetado puede estar justificado, pero hay muchas otras preocupaciones también, con respecto a la elección de tipo (por ejemplo, Integer tenía 2 bytes en Delphi de 16 bits, pero 4 bytes posteriormente).

Delphi intenta usar reglas compatibles con C para la alineación. En el pasado, tenía algunos errores aquí (particularmente con registros como TRec = registro A, B: extremo extendido, versus TRec = registro A: extendido; B: extremo extendido;), pero estos errores deberían corregirse ahora

+0

Muy interesante, gracias. Espero que Extendido sobreviva en el compilador de 64 bits y no se duplique alias. – kludg

+0

Es una pena que el alineamiento implícito empaquetado = 1 para los registros no esté documentado. Al menos no fue la última vez que miré, cuando me encontré con el problema. –

0

Delphi XE Ayuda dice esto para matrices dinámicas

diseño de memoria matriz dinámica (Win32 únicamente):

Contenido

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

Así, por ese documento que está lleno de Offset.

Cuestiones relacionadas