En informática , un registro (también llamado estructura , struct o tipo de datos compuesto ) es una estructura de datos compuesta : una colección de campos , posiblemente de diferentes tipos de datos , generalmente fijos en número y secuencia. [1]
Por ejemplo, una fecha podría almacenarse como un registro que contenga un campo numérico de año , un campo de mes representado como una cadena y un campo numérico de día del mes . Un registro circular podría contener un radio numérico y un centro que es un registro de punto que contiene las coordenadas x e y .
Entre las aplicaciones más destacadas se incluyen el lenguaje de programación de tipo registro y el almacenamiento basado en filas, datos organizados como una secuencia de registros, como una tabla de base de datos , una hoja de cálculo o un archivo de valores separados por comas (CSV). En general, un valor de tipo registro se almacena en la memoria y el almacenamiento basado en filas se realiza en el almacenamiento masivo .
Un tipo de registro es un tipo de datos que describe dichos valores y variables. La mayoría de los lenguajes de programación modernos permiten al programador definir nuevos tipos de registros. La definición incluye especificar el tipo de datos de cada campo y un identificador (nombre o etiqueta) mediante el cual se puede acceder a él. En la teoría de tipos , los tipos de producto (sin nombres de campo) son generalmente los preferidos debido a su simplicidad, pero los tipos de registros adecuados se estudian en lenguajes como System F-sub . Dado que los registros de teoría de tipos pueden contener campos tipificados por funciones de primera clase además de datos, pueden expresar muchas características de la programación orientada a objetos .
En el contexto del almacenamiento, como en una base de datos o una hoja de cálculo, a menudo un registro se denomina fila y cada campo se denomina columna . [2] [3] [4] [5]
En la programación orientada a objetos , un objeto es un registro que contiene campos de estado y método.
Un registro es similar a una tupla matemática , aunque una tupla puede o no considerarse un registro, y viceversa, dependiendo de las convenciones y del lenguaje de programación. En la misma línea, un tipo de registro puede verse como el análogo en lenguaje informático del producto cartesiano de dos o más conjuntos matemáticos , o la implementación de un tipo de producto abstracto en un lenguaje específico.
Un registro se diferencia de una matriz en que los elementos de un registro (campos) están determinados por la definición del registro y pueden ser heterogéneos, mientras que una matriz es una colección de elementos con el mismo tipo. [6]
Los parámetros de una función se pueden considerar colectivamente como los campos de un registro y el paso de argumentos a la función se puede considerar como la asignación de los parámetros de entrada a los campos del registro. En un nivel bajo, una llamada de función incluye un registro de activación o marco de llamada , que contiene los parámetros, así como otros campos, como variables locales y la dirección de retorno.
El concepto de registro se remonta a varios tipos de tablas y libros de contabilidad utilizados en contabilidad desde tiempos remotos. La noción moderna de registros en informática, con campos de tipo y tamaño bien definidos, ya estaba implícita en las calculadoras mecánicas del siglo XIX, como la máquina analítica de Babbage . [7] [8]
El medio legible por máquina original utilizado para los datos (en oposición al control) fue la tarjeta perforada utilizada para los registros en el Censo de los Estados Unidos de 1890 : cada tarjeta perforada era un solo registro. Compare la entrada del diario de 1880 y la tarjeta perforada de 1895. Los registros estaban bien establecidos en la primera mitad del siglo XX, cuando la mayor parte del procesamiento de datos se realizaba utilizando tarjetas perforadas. Por lo general, cada registro de un archivo de datos se registraba en una tarjeta perforada, con columnas específicas asignadas a campos específicos. Generalmente, un registro era la unidad más pequeña que se podía leer desde un almacenamiento externo (por ejemplo, lector de tarjetas, cinta o disco). El contenido de los registros de estilo tarjeta perforada se llamaba originalmente "registros unitarios" porque las tarjetas perforadas tenían longitudes de documento predeterminadas. [9] Cuando los sistemas de almacenamiento se volvieron más avanzados con el uso de discos duros y cintas magnéticas , los registros de longitud variable se convirtieron en el estándar. Un registro de longitud variable es un registro en el que el tamaño del registro en bytes es aproximadamente igual a la suma de los tamaños de sus campos. Esto no era posible hacerlo antes de que se inventara el hardware de almacenamiento más avanzado porque todas las tarjetas perforadas tenían que ajustarse a longitudes de documentos predeterminadas que la computadora podía leer, ya que en ese momento las tarjetas tenían que introducirse físicamente en una máquina.
La mayoría de las implementaciones de lenguaje de máquina y los primeros lenguajes ensambladores no tenían una sintaxis especial para los registros, pero el concepto estaba disponible (y se usaba ampliamente) mediante el uso de registros de índice , direccionamiento indirecto y código automodificable . Algunas de las primeras computadoras, como la IBM 1620 , tenían soporte de hardware para delimitar registros y campos, e instrucciones especiales para copiar dichos registros.
El concepto de registros y campos fue central en algunas de las primeras utilidades de clasificación y tabulación de archivos , como el Report Program Generator (RPG) de IBM .
COBOL fue el primerlenguaje de programaciónen admitir tipos de registros[10],y sus herramientas de definición de registros eran bastante sofisticadas en ese momento. El lenguaje permite la definición de registros anidados con campos alfanuméricos, enteros y fraccionarios de tamaño y precisión arbitrarios, y campos que dan formato automáticamente a cualquier valor que se les asigne (por ejemplo, inserción de signos monetarios, puntos decimales y separadores de grupos de dígitos). Cada archivo está asociado con una variable de registro en la que se leen o escriben datos. COBOL también proporciona unaMOVE
CORRESPONDING
declaración que asigna los campos correspondientes de dos registros según sus nombres.
Los primeros lenguajes desarrollados para computación numérica, como FORTRAN (hasta FORTRAN IV ) y ALGOL 60 , no admitían tipos de registro; pero versiones posteriores de esos lenguajes, como FORTRAN 77 y ALGOL 68, sí los añadieron. El lenguaje de programación Lisp original también carecía de registros (excepto por el cons cell incorporado ), pero sus expresiones S proporcionaban un sustituto adecuado. El lenguaje de programación Pascal fue uno de los primeros lenguajes en integrar completamente los tipos de registro con otros tipos básicos en un sistema de tipos lógicamente consistente. El lenguaje PL/I proporcionó registros de estilo COBOL. El lenguaje C proporciona el concepto de registro utilizando struct
s. La mayoría de los lenguajes diseñados después de Pascal (como Ada , Modula y Java ) también admitían registros.
Aunque los registros ya no se utilizan a menudo en su contexto original (es decir, se utilizan únicamente con el propósito de contener datos), los registros influyeron en los lenguajes de programación orientados a objetos más nuevos y en los sistemas de gestión de bases de datos relacionales . Dado que los registros proporcionaban más modularidad en la forma en que se almacenaban y manejaban los datos, son más adecuados para representar conceptos complejos del mundo real que los tipos de datos primitivos proporcionados por defecto en los lenguajes. Esto influyó en lenguajes posteriores como C++ , Python , JavaScript y Objective-C que abordan las mismas necesidades de modularidad de la programación. [11] Los objetos en estos lenguajes son esencialmente registros con la adición de métodos y herencia , que permiten a los programadores manipular la forma en que se comportan los datos en lugar de solo el contenido de un registro. Muchos programadores consideran que los registros son obsoletos ahora, ya que los lenguajes orientados a objetos tienen características que superan con creces lo que los registros son capaces de hacer. Por otro lado, muchos programadores argumentan que la baja sobrecarga y la capacidad de usar registros en lenguaje ensamblador hacen que los registros sigan siendo relevantes cuando se programa con bajos niveles de abstracción . Hoy en día, los lenguajes más populares en el índice TIOBE , un indicador de la popularidad de los lenguajes de programación, han sido influenciados de alguna manera por los registros debido al hecho de que están orientados a objetos. [12] Los lenguajes de consulta como SQL y Object Query Language también fueron influenciados por el concepto de registros. Estos lenguajes permiten al programador almacenar conjuntos de datos, que son esencialmente registros, en tablas. [13] Estos datos luego se pueden recuperar utilizando una clave principal . Las tablas en sí mismas también son registros que pueden tener una clave externa : una clave que hace referencia a datos en otra tabla.
Las operaciones para un tipo de registro incluyen:
Algunos lenguajes proporcionan funciones que enumeran los campos de un registro. Esta función es necesaria para implementar ciertos servicios, como depuración , recolección de basura y serialización . Requiere cierto grado de polimorfismo de tipos .
En contextos que admiten la subtipificación de registros, las operaciones incluyen agregar y eliminar campos de un registro. Un tipo de registro específico implica que está presente un conjunto específico de campos, pero los valores de ese tipo pueden contener campos adicionales. Un registro con campos x , y y z pertenecería entonces al tipo de registros con campos x e y , al igual que un registro con campos x , y y r . La razón es que pasar un registro ( x , y , z ) a una función que espera un registro ( x , y ) como argumento debería funcionar, ya que esa función encontrará todos los campos que requiere dentro del registro. Muchas formas de implementar registros de manera práctica en lenguajes de programación tendrían problemas para permitir tal variabilidad, pero el asunto es una característica central de los tipos de registros en contextos más teóricos.
La mayoría de los lenguajes permiten la asignación entre registros que tienen exactamente el mismo tipo de registro (incluidos los mismos tipos de campos y nombres, en el mismo orden). Sin embargo, según el lenguaje, dos tipos de datos de registros definidos por separado pueden considerarse tipos distintos incluso si tienen exactamente los mismos campos.
Algunos lenguajes también pueden permitir la asignación entre registros cuyos campos tienen nombres diferentes, haciendo coincidir cada valor de campo con la variable de campo correspondiente por sus posiciones dentro del registro; de modo que, por ejemplo, un número complejo con campos llamados real
y imag
puede asignarse a una variable de registro de punto 2D con campos X
y Y
. En esta alternativa, todavía se requiere que los dos operandos tengan la misma secuencia de tipos de campo. Algunos lenguajes también pueden requerir que los tipos correspondientes tengan el mismo tamaño y codificación, de modo que todo el registro pueda asignarse como una cadena de bits no interpretada . Otros lenguajes pueden ser más flexibles en este sentido y solo requieren que cada campo de valor pueda asignarse legalmente al campo de variable correspondiente; de modo que, por ejemplo, un campo entero corto puede asignarse a un campo entero largo , o viceversa.
Otros lenguajes (como COBOL ) pueden hacer coincidir campos y valores por sus nombres, en lugar de por sus posiciones.
Estas mismas posibilidades se aplican a la comparación de dos valores de registro para determinar su igualdad. Algunos idiomas también pueden permitir comparaciones de orden ('<' y ">'), utilizando el orden lexicográfico basado en la comparación de campos individuales. [ cita requerida ]
PL/I permite ambos tipos de asignación anteriores y también permite expresiones de estructura , como a = a+1;
donde "a" es un registro, o estructura en la terminología PL/I.
En Algol 68, si Pts
era una matriz de registros, cada uno con campos enteros X
y Y
, se podía escribir para obtener una matriz de enteros, que constaba de los campos de todos los elementos de . Como resultado, las instrucciones y tendrían el mismo efecto.Y of Pts
Y
Pts
Y of Pts[3] := 7
(Y of Pts)[3] := 7
En Pascal , el comando with R do S
ejecutaría la secuencia de comandos S
como si todos los campos del registro R
se hubieran declarado como variables. De manera similar a la introducción de un espacio de nombres diferente en un lenguaje orientado a objetos como C# , ya no es necesario utilizar el nombre del registro como prefijo para acceder a los campos. Por lo tanto, en lugar de escribir, Pt.X := 5; Pt.Y := Pt.X + 3
se podría escribir .with Pt do begin X := 5; Y := X + 3 end
La representación de un registro en la memoria varía según el lenguaje de programación. A menudo, los campos se almacenan en ubicaciones de memoria consecutivas, en el mismo orden en que se declaran en el tipo de registro. Esto puede dar como resultado que dos o más campos se almacenen en la misma palabra de memoria; de hecho, esta característica se utiliza a menudo en la programación de sistemas para acceder a bits específicos de una palabra. Por otro lado, la mayoría de los compiladores agregarán campos de relleno, en su mayoría invisibles para el programador, para cumplir con las restricciones de alineación impuestas por la máquina (por ejemplo, que un campo de punto flotante debe ocupar una sola palabra).
Algunos lenguajes pueden implementar un registro como una matriz de direcciones que apuntan a los campos (y, posiblemente, a sus nombres y/o tipos). Los objetos en lenguajes orientados a objetos suelen implementarse de formas bastante complicadas, especialmente en lenguajes que permiten la herencia de múltiples clases .
Un registro autodefinido es un tipo de registro que contiene información para identificar el tipo de registro y localizar información dentro del registro. Puede contener los desplazamientos de los elementos; por lo tanto, los elementos se pueden almacenar en cualquier orden o se pueden omitir. [14] La información almacenada en un registro autodefinido se puede interpretar como metadatos para el registro, que es similar a lo que uno esperaría encontrar en los metadatos de UNIX con respecto a un archivo, que contiene información como la hora de creación del registro y el tamaño del registro en bytes . Alternativamente, varios elementos del registro, cada uno de los cuales incluye un identificador de elemento, pueden simplemente seguirse unos a otros en cualquier orden.
Un registro, especialmente en el contexto del almacenamiento basado en filas, puede incluir campos clave que permiten indexar los registros de una colección. Una clave principal es única en todos los registros almacenados; solo existe una de esta clave. [15] En otras palabras, no puede existir ningún duplicado para ninguna clave principal. Por ejemplo, un archivo de empleado puede contener número de empleado, nombre, departamento y salario. El número de empleado será único en la organización y será la clave principal. Dependiendo del medio de almacenamiento y la organización del archivo, el número de empleado puede estar indexado , es decir, también se almacena en un archivo separado para que la búsqueda sea más rápida. El código de departamento no es necesariamente único; también puede estar indexado, en cuyo caso se consideraría una clave secundaria o una clave alternativa . [16] Si no está indexado, se tendría que escanear todo el archivo de empleados para producir una lista de todos los empleados de un departamento específico. Las claves generalmente se eligen de una manera que minimice las posibilidades de que una clave pueda asignar varios valores de manera factible. Por ejemplo, el campo de salario normalmente no se consideraría utilizable como clave, ya que es probable que muchos empleados tengan el mismo salario.