Compartir a través de


Diseño del puntero

El diseño del puntero describe punteros de una estructura o una matriz.

pointer_layout<>

Un campo pointer_layout<> consta de los caracteres de formato FC_PP FC_PAD seguidos de una o varias descripciones de puntero, como se describe más adelante, y termina con un carácter de formato FC_END:

FC_PP
FC_PAD
{ pointer_instance_layout<> }*
FC_END

Un campo pointer_instance_layout<> es una cadena de formato que describe una o varias instancias de punteros. En estos descriptores se usan los siguientes campos:

  • offset_in_memory

    Desplazamiento especificado hasta la ubicación del puntero en la memoria. Para un puntero que reside en una estructura, este desplazamiento es un desplazamiento negativo desde el final de la estructura (el final de la parte no conforme de las estructuras conformes); para las matrices, el desplazamiento es desde el principio de la matriz.

  • offset_in_buffer

    Desplazamiento especificado hasta la ubicación del puntero en el búfer. Para un puntero que reside en una estructura, este desplazamiento es un desplazamiento negativo desde el final de la estructura (el final de la parte no conforme de las estructuras conformes); para las matrices, el desplazamiento es desde el principio de la matriz.

  • offset_to_array

    Desplazamiento de una estructura contenedora hasta la matriz incrustada cuyos punteros se están controlando. En el caso de las matrices de nivel superior, este campo siempre será cero.

  • del entrenamiento

    Número total de punteros que tienen el mismo diseño<> descrito.

  • increment

    Incremento entre punteros sucesivos durante una repetición.

  • number_of_pointers

    Número de punteros diferentes en una instancia de repetición.

  • pointer_description

    Descripción del puntero.

Todos los diseños de instancia de puntero usan el siguiente campo único pointer_instance<8>:

offset_to_pointer_in_memory<2> 
offset_to_pointer_in_buffer<2> 
pointer_description<4>

A continuación se muestran descriptores de instancia:

Instancia única de un puntero a un tipo simple:

FC_NO_REPEAT FC_PAD 
pointer_instance<8>

Puntero de repetición fijo:

FC_FIXED_REPEAT FC_PAD 
iterations<2> 
increment<2> 
offset_to_array<2> 
number_of_pointers<2>
{ pointer_instance<8> }*

Puntero de repetición variable:

FC_VARIABLE_REPEAT (FC_FIXED_OFFSET | FC_VARIABLE_OFFSET) 
increment<2> 
offset_to_array<2> 
number_of_pointers<2> 
{ pointer_instance<8> }*

En el caso de las instancias fijas de puntero de repetición y repetición variable, hay un conjunto de descripciones de desplazamiento y puntero para cada puntero de la instancia de repetición.

Problemas de diseño de punteros

En esta sección se tratan los problemas relacionados con el procesamiento de estructuras conformes y punteros incrustados. El problema es que el compilador genera diseños de puntero para estructuras y matrices con cierta redundancia. Esto es beneficioso, ya que la información es útil y, por ejemplo, una estructura conforme puede desplazarse por un diseño de puntero para prestar servicio a todos los punteros de la estructura y de la matriz conforme que forman parte de la estructura conforme. Pero existen algunas situaciones que requieren que el motor de NDR realice un trabajo adicional para procesar todos los diseños de puntero en la secuencia adecuada, procesando cada puntero solo una vez.

Lo que genera el compilador

Cada objeto descrito en esta sección tiene punteros; es decir, por ejemplo, una estructura conforme tiene punteros en la parte de estructura, así como en los elementos de matriz. El elemento es una estructura simple con un puntero.

  1. Estructura conforme, nivel único

    El descriptor conforme tiene una parte PP donde se describen todos los punteros, tanto de la estructura como de la matriz. La lista de miembros tiene FC_LONG en lugar de un puntero. El descriptor de matriz CARRAY contiene elementos mediante el uso de un embedded_complex y ningún descriptor de puntero. El elemento sigue incluyendo su descriptor de puntero único. En una estructura conforme y descriptores de estructura simples, el diseño del puntero precede al diseño de miembro.

  2. Estructura conforme, dos o más niveles

    La descripción de PP incluye punteros de todos los niveles. Reutiliza la misma descripción de la matriz que la estructura conforme interna. La lista de miembros tiene FC_LONG en lugar de un puntero. Una estructura incrustada pasa por el uso de un complejo incrustado. El descriptor de estructura conforme se reutiliza tal cual. El tamaño de la parte plana de la estructura también se completa, lo que significa que el tamaño de la estructura de nivel superior incluye el tamaño plano de la estructura incrustada.

  3. Estructura compleja, nivel único

    Los miembros del puntero están marcados por el campo FC_POINTER. El diseño del puntero se simplifica de forma que haya un descriptor de puntero (4 bytes) para cada entrada FC_POINTER de la lista. El diseño del puntero se recorre en paralelo con un recorrido de miembro, es decir, un FC_POINTER hace que se procese la siguiente descripción del puntero. La matriz CARRAY tiene un diseño de puntero con todos los descriptores de la matriz y, a continuación, del elemento, mediante el uso de una estructura compleja incrustada. El descriptor de elemento se reutiliza. El tamaño de la parte plana de la estructura se completa, lo que significa que el tamaño plano de la estructura de nivel superior incluye el tamaño plano de la estructura incrustada. En estructuras complejas, el diseño de miembro precede al diseño del puntero.

    Por lo tanto, la generación de una descripción de matriz conforme es diferente en función de si se trata de una matriz dentro de una estructura conforme o dentro de una estructura compleja.

  4. Estructura compleja, dos o más niveles, compleja dentro de compleja

    La estructura compleja de nivel superior tiene sus punteros de miembro y la estructura compleja incrustada tiene sus punteros de miembro. Se reutiliza el descriptor de estructura conforme. El descriptor de matriz de la parte superior es la matriz reutilizada de la estructura incrustada.

  5. Estructura compleja con una estructura conforme incrustada

    La estructura conforme de nivel superior tiene sus punteros de miembro. El descriptor de estructura conforme se reutiliza tal cual. El descriptor de matriz se reutiliza a partir de la estructura conforme incrustada; es decir, no tiene punteros en el descriptor de matriz. El elemento tiene su descriptor de puntero.

  6. Matrices de estructuras con punteros

    Se genera una matriz de estructuras sencillas con punteros como SMFARRAY o CARRAY dependiendo de si la matriz tiene un tamaño específico, pero en ambos casos tiene un diseño de puntero completo (FIXED_REPEAT o VARIABLE_REPEAT). El diseño del puntero se coloca delante del diseño del miembro.

    Se genera una matriz de estructuras complejas con punteros como BOGUS_ARRAY, independientemente de si es fija o con un tamaño concreto y, en ambos casos, no tiene ningún diseño de puntero.

Qué hace el motor de NDR

En esta sección se describe el comportamiento del motor de NDR.

Paso de serialización

  1. Estructuras conformes y estructura conforme incrustada.

    La estructura de nivel superior se comporta como una estructura de nivel único.

  2. Estructura compleja incrustada con matriz conforme

    Cualquier estructura compleja obliga a la estructura externa a ser una estructura compleja. La estructura incrustada nunca serializa su matriz. Toda estructura pasa siempre por punteros incrustados serializando miembros, y uno de los miembros es FC_POINTER.

  3. Estructura compleja con una estructura conforme

    La estructura conforme incrustada superior serializa la matriz conforme y todos los punteros. El motor de NDR nunca desciende a estructuras conformes anidadas más profundas si hay alguna. Esto simplifica la solución, ya que una estructura conforme es un objeto hoja en lo que respecta a la serialización de objetos incrustados. La estructura compleja de nivel superior omite la serialización de matrices.

Pasos de deserialización, aplicación de tamaño de búfer y liberación

La deserialización es simétrica a la serialización. La primera operación que realiza para estructuras complejas es averiguar la ubicación de los punteros en el búfer mediante la llamada a la función NdrComplexStructBufferSize. Después, se deserializan los punteros en paralelo, lo que permite que se use correctamente el mismo esquema para deserializar los punteros. No debería haber confusión sobre los objetos y uniones con tamaño específico. La imagen de la memoria no debe usarse para objetos y uniones con tamaño, solo para el contenido del búfer.

Las marcas que se usan para realizar serializaciones y deserializaciones correctamente se usan de la misma manera para el cambio de tamaño del búfer y la liberación con el fin de asegurarse de que los punteros se recorren exactamente una vez.

Paso de endianidad

Al principio, el paso de endianidad es algo similar a la serialización/deserialización; se requieren dos pasos para procesar estructuras complejas. El primer paso convierte la parte plana y busca la ubicación de los punteros en el búfer de forma similar a cómo se deserializa mediante un cambio de tamaño del búfer. Después, el segundo paso convierte los punteros.

Los pasos de endianidad difieren de la siguiente manera: cada estructura y cada miembro debe ser escalonado hasta que el elemento o miembro hoja sea un tipo simple. Esto es diferente de la deserialización; en ese caso, por ejemplo, nunca es necesario procesar estructuras conformes incrustadas en estructuras conformes, ni cualquier miembro de la estructura conforme, por ese motivo. Otro problema es que la conversión no es una operación idempotente; por lo tanto, el paso de deserialización podría rehacer la deserialización de algunas piezas sin provocar daños, mientras que la conversión debe realizarse estrictamente una vez por cada tipo simple.

Por lo tanto, el algoritmo de endianidad se puede resumir de la siguiente manera. NDR tiene una noción de la estructura conforme de nivel superior y una marca para señalarla, según corresponda. Al realizar el recorrido por primera vez, como convertir la parte plana y obtener la ubicación de los punteros, esta noción no se usa. NDR desciende mediante las partes planas de todos los niveles de las estructuras y nunca se aventura en el procesamiento de punteros. Por último, NDR convierte la matriz en el nivel superior.

Al realizar el recorrido por segunda vez, la marca se usa para señalar el pase del puntero incrustado a fin de evitar entrar en niveles más profundos de las estructuras conformes y, después, la estructura conforme de nivel superior. De este modo, la marca fuerza el comportamiento común de serialización/deserialización, que es evitar que se descienda en niveles más profundos de estructuras conformes.

El segundo paso para estructuras complejas con matrices conformes funciona de la siguiente manera: las estructuras complejas funcionan de la manera común, lo que significa que los niveles más profundos nunca aplican u omiten su tamaño conforme o sus matrices conformes, y prefieren simplemente recorrer los miembros sin tocar la matriz.

En el caso de estructuras complejas con estructuras conformes, se debe tener en cuenta si la estructura conforme es de nivel superior y si se encuentra en una estructura compleja. La parte plana de la matriz se procesa mediante la estructura conforme superior. En el segundo paso, la estructura conforme superior omite la parte plana, recorre el diseño del puntero y vuelve. La estructura compleja superior omite su parte plana y también el diseño del puntero.

El aspecto sólido de los recorridos de endianidad

El recorrido de endianidad comprueba las condiciones habituales fuera del búfer y realiza otras comprobaciones de una naturaleza no relacionada. Las comprobaciones destinadas a valores correlacionados (como el argumento de ajuste de tamaño frente al tamaño conforme) no se pueden realizar mediante este paso; se realizan más adelante, cuando se realiza la deserialización.