full - delphi versiones
¿Qué significa "alineación de registros de bytes de fuerzas empaquetadas ahora"? (4)
Como yo no soy el tipo de compilador de Delphi, también puedo adivinar como lo hicieron los demás: la alineación de registros podría no estar destinada a alinear los miembros dentro del registro, sino el registro en sí mismo.
Si declara una variable de registro, está alineada con alguna dirección en la memoria, lo más probable es que esté alineada en un límite de 4 bytes. Este ha sido el caso (como se probó en D2007) para registros empaquetados y desempacados.
Ahora en XE2 se coloca un registro empaquetado en un límite de 1 byte, mientras que los registros desempaquetados se colocan en un límite par, que se puede controlar con la palabra clave align. Me gusta esto:
type
TRecAligned = record
b1: byte;
u1: uint64;
end align 16;
TRecPackedAligned = packed record
b1: byte;
u1: uint64;
end align 16;
El registro empaquetado todavía está alineado en un límite de 1 byte mientras que el registro desempaquetado está alineado con un límite de 16 bytes.
Como dije, es solo una suposición. La redacción de la cita de Embarcadero no es tan clara en el asunto.
Lo nuevo para Delphi XE2 contiene lo following .
Empaquetado ahora Forces Byte Alineación de registros
Si tiene un código heredado que usa el tipo de registro empaquetado y desea vincularlo con un archivo DLL externo o con C ++, debe eliminar la palabra "empaquetada" de su código. La palabra clave packed ahora fuerza la alineación de bytes, mientras que en el pasado no necesariamente hacía esto. El cambio de comportamiento está relacionado con los cambios de compatibilidad de alineación de C ++ en Delphi 2009.
No entiendo esto. Estoy luchando con este punto: mientras que en el pasado no necesariamente hacía esto . Lo que no puedo conciliar es que el paquete siempre ha resultado en el alineamiento de bytes de los registros a mi leal saber y entender. ¿Alguien puede dar un ejemplo de un registro empaquetado que no está alineado por bytes? Obviamente, esto tendría que ser en una versión anterior.
¿Por qué los documentos dicen "si desea establecer un enlace con una DLL externa o con C ++, necesita eliminar la palabra empaquetada de su código"? Si el código externo usa #pragma pack(1)
, ¿qué debemos hacer si el empaquetado no está permitido?
¿Qué pasa con la directiva $ALIGN
? ¿Son {$A1} and {$A-}
equivalentes al packed
o hay algún significado adicional con el packed
?
Parece que me falta algo y agradecería que alguien pudiera explicar esto. ¿O la documentación es realmente pobre?
Actualizar
Estoy razonablemente convencido de que la documentación se refiere a la alineación del registro en sí, más que a la disposición del registro. Aquí hay un pequeño programa que muestra que el uso del packed
en un registro obliga a la alineación del registro a ser 1.
program PackedRecords;
{$APPTYPE CONSOLE}
type
TPackedRecord = packed record
I: Int64;
end;
TPackedContainer = record
B: Byte;
R: TPackedRecord;
end;
TRecord = record
I: Int64;
end;
TContainer = record
B: Byte;
R: TRecord;
end;
var
pc: TPackedContainer;
c: TContainer;
begin
Writeln(NativeInt(@pc.R)-NativeInt(@pc.B));//outputs 1
Writeln(NativeInt(@c.R)-NativeInt(@c.B));//outputs 8
Readln;
end.
Esto produce la misma salida en Delphi 6, 2010, XE y XE2 de 32 bits y XE de 64 bits.
Las últimas actualizaciones de la documentación han eliminado todo el texto en el que se basaba esta pregunta. Mi conclusión es que el texto original fue simplemente un error de documentación.
Por lo que recuerdo, el record
solía estar empaquetado desde una versión del compilador alrededor de Delphi 5-6.
Luego, por razones de rendimiento, los campos de record
simple se alinearon, de acuerdo con la configuración en la opción del proyecto. Si define un packed record
, no habrá ninguna alineación dentro del registro.
El texto que está citando parece relacionado no específicamente con XE2, sino con un cambio de Delphi 2009. Vea esta entrada en el blog con un propósito histórico.
Supongo que la alineación de registros '''' Packed ''Now Forces Byte of Records'' ''se refiere a la característica Delphi 2009 {$OLDTYPELAYOUT ON}
, que puede tener algún problema de implementación antes de XE2. Estoy de acuerdo contigo: parece un problema de documentación.
pascal siempre ha soportado estructuras empaquetadas que probablemente sean más fáciles de explicar usando un ejemplo
Digamos que tienes dos arreglos xey, y que estamos usando un procesador de 16 bits. Es decir, el tamaño de ''palabra'' del procesador es de 16 bits.
myrec =
record
b : byte;
i : integer;
end;
x : array[1..10] of myrec;
y : packed array[1..10] of myrec;
Pascal solo le dice que tiene 10 elementos para trabajar, cada uno contiene 3 bytes de información (supongamos que el entero es la variedad antigua de 16 bits). En realidad, no dice nada sobre cómo se almacena esa información. Puede suponer que la matriz se almacena en 30 bytes consecutivos, sin embargo, esto no es necesario y es completamente dependiente del compilador (una buena razón para evitar las matemáticas de puntero).
Un compilador puede poner un byte ficticio entre los valores de campo byi para garantizar que tanto by como caen en los límites de las palabras. En este caso, la estructura tomará un total de 40 bytes.
La palabra reservada ''empaquetada'' instruye al compilador a optimizar el tamaño sobre la velocidad, mientras que al salir empaquetado, el compilador generalmente optimizará la velocidad sobre el tamaño. En este caso, la estructura se optimizaría y podría tomar solo 30 bytes.
Nuevamente digo ''podría'' porque todavía depende del compilador. La palabra clave ''empaquetada'' solo dice que compacte los datos, pero en realidad no dice cómo. Por lo tanto, algunos compiladores simplemente ignoraron la palabra clave, mientras que otros utilizaron el paquete para inhabilitar la alineación de palabras.
En el caso de este último, lo que típicamente podría suceder es que cada elemento esté alineado con el tamaño de la palabra del procesador. Debes darte cuenta aquí de que el tamaño de palabra del procesador es típicamente el tamaño de registro, no simplemente ''16 bits ''como comúnmente ha venido a significar. En el caso de un procesador de 32 bits, por ejemplo, el tamaño de palabra es de 32 bits (aunque definimos genéricamente palabras como 16 bits, esto es solo un retroceso histórico). En cierto sentido, es el equivalente de "memoria" de un sector de disco.
Al empacar los datos, podría tener valores como el entero cruzando los límites de las palabras, lo que requeriría más manipulación de la memoria (muy similar a la necesidad de leer dos sectores de disco si un registro cruza un límite del sector).
Entonces, básicamente, lo que significa el cambio es que Delphi ahora usa completamente la palabra clave empaquetada y forzando la alineación de bytes (sobre la alineación de palabras) todo el tiempo.
Espero que esto sea suficiente para explicarlo. En realidad, es un tema más grande que puedo responder razonablemente en unos pocos párrafos.
ACTUALIZACIÓN, continuación del hilo de comentarios a continuación ...
DavidH> No puedo imaginar que quieras decir que el compilador es capaz de producir resultados diferentes con una entrada idéntica
Sí David, eso es exactamente lo que estoy diciendo. No necesariamente de una compilación a la siguiente en el mismo compilador, pero ciertamente entre versiones de compilador, marcas de compilador y plataformas diferentes.
TonyH> Creo que la mayoría de nosotros siempre asumimos que el pack = byte está alineado, así que ahora nos estamos rascando la cabeza buscando un escenario donde no sea así. @David Heffernan pregunta si alguien sabe uno
Tony, has dado en el clavo aquí. Ha asumido que el empaquetado funciona como una directiva de compilación que especifica cómo se organiza la memoria de datos. Esto no es lo que significa. Una mejor analogía es considerar la directiva de optimización para la generación de código. Usted sabe que el código está siendo optimizado, pero no necesariamente especifica cuál será el código subyacente, ni lo necesita.
Puedo darte muchos ejemplos. Digamos que tienes lo siguiente (estoy usando una matriz, podría aplicarse con la misma facilidad a un registro)
myarray = packed array[1..8] of boolean
Si luego imprime un SizeOf (myarray), ¿qué esperaría? La respuesta es que Delphi no garantiza que el paquete se implemente de manera particular. Por lo tanto, la respuesta podría ser de 8 bytes (si está alineando byte cada elemento). Es tan válido para Delphi empaquetar estos como bits, por lo que toda la matriz podría caber en 1 byte. Podría ser de 16 bytes si el compilador decide no optimizar los límites de bytes y se ejecuta en una arquitectura de 16 bits. Sí, sería menos eficiente en términos de velocidad, pero el objetivo principal del embalaje es optimizar el tamaño sobre la velocidad. Cualquier cosa que haga es invisible para el desarrollador siempre y cuando simplemente acceda a los elementos de la matriz y no haga suposiciones y pruebe sus propias matemáticas de puntero para acceder a los datos subyacentes.
De manera similar, ni siquiera se puede garantizar la organización interna de una primitiva: depende de la plataforma, no depende del compilador. Por ejemplo, si ha trabajado en varias arquitecturas, tendrá en cuenta las cuestiones relacionadas con la cantidad de bits que componen un número entero; si los bytes dentro de ese entero se almacenan o no en orden de bytes u orden de bytes inversos.
Estos tipos de problemas arquitectónicos son exactamente la razón por la que se han desarrollado diversas técnicas como archivo delimitado por comas, xml, etc. Para proporcionar una plataforma común confiable.
Para resumir, David, el problema es que en realidad estás haciendo la pregunta incorrecta. Si considera la cita de Embarcadero en el contexto de lo que dije, verá que es consistente con lo que estoy diciendo.