Registros y Registros Variantes Arreglos Lenguajes de Programación I Tipos de Datos Compuestos Ernesto Hernández-Novich <[email protected]> c 2006-2010 Copyright Cadenas Registros y Registros Variantes Arreglos Registros Registros – agrupan datos de tipos heterogéneos para almacenarlos y manipularlos en conjunto. También son llamados Estructuras (structures). Cada componente se denomina campo (field). En la mayoría de los lenguajes, las declaraciones de registros pueden anidarse. Equivalen al concepto matemático de n-upla. Cadenas Registros y Registros Variantes Arreglos Declarando Registros En C struct elemento { int numero_atomico; char nombre[2]; double peso_atomico; int es_metalico; }; En Pascal type elemento = record numero_atomico : integer; nombre : array[1..2] of char; peso_atomico : real; es_metalico : boolean end; Cadenas Registros y Registros Variantes Arreglos Usando Registros Operador sintáctico para acceso a los campos – tradicionalmente es el punto. En C struct elemento carbono; carbono.numero_atomico = 12; if (carbono.es_metalico) { ... } En Pascal var cobre : elemento; cobre.nombre := ’Cu’; cobre.es_metalico := true; En Fortran se escribe carbono %nombre. Cadenas Registros y Registros Variantes Arreglos Cadenas Almacenamiento de Registros Los campos se almacenan en ubicaciones contiguas. El compilador/interpretador calcula los desplazamientos desde la base de almacenamiento hasta cada campo. Optimizar para velocidad (lo usual). Campos alineados con límites de palabra en hardware. Espacios vacíos entre los campos. Optimizar para espacio (opcional en Pascal) Registros empaquetados (packed) – no hay espacio entre los campos. Necesita más instrucciones para acceso. Lo mejor de ambos mundos se obtiene reordenando los campos – costoso de implantar en el compilador. ¿Es posible compararlos directamente? Registros y Registros Variantes Arreglos Velocidad vs. Espacio Restricciones de la arquitectura Supongamos que en la arquitectura int ocupa 32 bits y debe alinearse a 32 bits. char ocupa 8 bits y debe alinearse a 16 bits – pero sus arreglos se disponen de manera contigua. float ocupa 64 bits y debe alinearse a 64 bits. bool ocupa 8 bits y debe alinearse a 16 bits. Las restricciones siempre son arbitrarias – respetarlas conduce a buen desempeño del lenguaje. ¿Cómo organizar este registro? struct meta { int foo; char bar[2]; int baz; double qux; bool meh; }; Cadenas Registros y Registros Variantes Arreglos Cadenas Para velocidad Respetar alineación a costa de espacio desperdiciado 4 bytes Dispuestos en el mismo orden de aparición. Alineados de forma óptima según reglas de la arquitectura. Ocupación: 28 bytes. 0 4 foo bar 8 Desperdicio: 9 bytes. 12 El primer campo del registro siempre está alineado según las reglas. 16 20 24 meh baz qux Registros y Registros Variantes Arreglos Cadenas Para espacio Un campo detrás de otro, sin alinear Dispuestos en el mismo orden de aparición. 4 bytes No se dejan espacios vacíos entre campos. 0 Ocupación: 28 bytes. 4 bar Desperdicio: 0 bytes. 8 baz El primer campo del registro siempre está alineado según las reglas. 12 16 foo baz qux meh Registros y Registros Variantes Arreglos Cadenas Balance Reordenar los campos Minimizar espacio – maximizar acceso. Reordenar no es trivial – equivale a knapsack que es NP-completo. Ocupación: 20 bytes. Desperdicio: 1 byte. 4 bytes 0 4 8 foo bar meh qux 12 16 baz Registros y Registros Variantes Arreglos Registros Variantes Colecciones alternativas de campos; sólo una válida. struct elemento { char nombre[2]; int numero_atomico; double peso_atomico; int es_metalico; int es_natural; union { struct { char *donde; double prevalencia; } natural; double tiempo_de_vida; } extra; } cobre; Cadenas Registros y Registros Variantes Arreglos Cadenas Registros Variantes Se originan en los equivalence de Fortran integer i real r logical b equivalence (i, r, b) ¿Cómo obligar a un uso correcto de las alternativas? Si no hay control, es un caso extremo de aliasing. Algunos lenguajes mantienen un campo escondido que establece cuál alternativa particular está vigente. Algunos lenguajes exigen un campo discriminante (Pascal) y hasta es obligatorio asignar campos al cambiar el discriminante (Ada). Registros y Registros Variantes Arreglos Arreglos Son una asociación entre un tipo índice a un tipo componente o tipo almacenado. En la mayoría de los lenguajes el tipo índice es entero, pero muchos lenguajes permiten cualquier tipo discreto. Para hacer referencia a un elemento dentro de un arreglo suele utilizarse un subíndice delimitado En Fortran y Ada se usa A(42). En Pascal y C se usa A[42]. Cadenas Registros y Registros Variantes Arreglos Declaración de Arreglos Agregando notación subíndice a una declaración escalar. C/C++ con la base en cero char letras[26]; En Fortran con la base en uno character dimension (1:26) :: letras Con un constructor especial. Como en Pascal var letras : array [’a’..’z’] of char Como en Ada letras : array (character range ’a’..’z’) of character Arreglos multidimensionales. Cadenas Registros y Registros Variantes Arreglos Cadenas Operaciones sobre Arreglos Obtener un elemento particular (acceso directo por subíndice) es el habitual. En lenguajes orientados a objetos se puede sobrecargar el operador de indexado (caso [] en C++, indexer en C#). Secciones de Arreglo (slices) como en Fortran y Perl. Fortran90 permite Comparar arreglos directamente. Utilizar operandos aritméticos sobre arreglos y obtener un arreglo resultante correspondiente. Búsqueda, transposición, permutación de subíndices. Registros y Registros Variantes Arreglos Cadenas Dimensiones, Límites y Almacenamiento El número de dimensiones y límites de un arreglo (su forma) pueden determinarse estática o dinámicamente. Vida Global, Forma Estática se almacena estáticamente. Vida Local, Forma Estática se almacena en la pila de ejecución. Vida Local, Forma Estática al elaborar se almacena en la pila pero con una indirección (parte fija vs. parte variable usando dope vectors). Vida Arbitraria, Forma Estática al elaborar (Java, C#) se almacenan en el heap y su tamaño nunca cambia. Vida Arbitraria, Forma Dinámica se almacena en el heap y su tamaño cambiante obliga a reubicación. Registros y Registros Variantes Arreglos Disposición en Memoria Se almacenan en posiciones contiguas de memoria. Para arreglos multidimensionales Orden por filas (row major order) – dos elementos consecutivos difieren en el último subíndice. Orden por columnas (column major order) – dos elementos consecutivos difieren en el primer subíndice. Fortran usa column major order, la mayoría de los lenguajes usa row major order. La disposición con apuntadores permite colocar filas a voluntad en la memoria, manteniendo apuntadores al primer elemento de cada una. Filas de diferente longitud son posibles – arreglos esparcidos o cadenas. Requiere código extra y con indirecciones. Cadenas Registros y Registros Variantes Arreglos Cadenas Calculando las direcciones Declaración A : array [ L1 ..U1 ] of array [ L2 ..U2 ] of array [ L3 ..U3 ] of e_type; Tamaño de cada dimensión S3 = sizeof(e_type) S2 = (U3 - L3 + 1) * S3 S1 = (U2 - L2 + 1) * S2 La dirección de A[i,j,k] será addressof (A) + (i − L1 ) ∗ S1 + (j − L2 ) ∗ S2 + (k − L3 ) ∗ S3 ¿Se podrá calcular a tiempo de compilación? Registros y Registros Variantes Arreglos Cadenas Arreglo de Caracteres vs. entidades especiales. Cadenas literales entre comillas simples o dobles. Caracteres literales vs. cadenas literales (como en C). Secuencias de escape para caracteres especiales. Longitud variable vs. longitud constante. Operaciones disponibles en el lenguaje vs. librerías. Cadenas