Articulo de referencia

Seguridad de tipo

En informática , la seguridad de tipos es el grado en que un lenguaje de programación desalienta o previene los errores de tipo . Los lenguajes con seguridad de tipos también se...

En informática , la seguridad de tipos es el grado en que un lenguaje de programación desalienta o previene los errores de tipo . Los lenguajes con seguridad de tipos también se denominan a veces lenguajes fuertemente o estrictamente tipados . Los comportamientos clasificados como errores de tipo por un lenguaje de programación dado suelen ser aquellos que resultan de intentos de realizar operaciones con valores que no son del tipo de datos apropiado , por ejemplo, intentar sumar una cadena a un entero .

La verificación de tipos puede ser estática (detectando posibles errores en tiempo de compilación ), dinámica (asociando información de tipo con valores en tiempo de ejecución y consultándolos según sea necesario para detectar errores inminentes) o una combinación de ambas. [ 1 ] La verificación dinámica de tipos a menudo permite ejecutar programas que serían inválidos con la verificación estática, pero a costa de introducir errores en tiempo de ejecución.

En el contexto de los sistemas de tipos estáticos (de compilación), la seguridad de tipos generalmente implica (entre otras cosas) la garantía de que el valor final de cualquier expresión será un miembro legítimo del tipo estático de dicha expresión. El requisito preciso es más complejo; véanse, por ejemplo, el subtipado y el polimorfismo para comprender mejor este aspecto.

Definiciones

Intuitivamente, la solidez del tipo se captura en la concisa afirmación de Robin Milner de que

Los programas bien tipados no pueden "fallar". [ 2 ]

En otras palabras, si un sistema de tipos es correcto , entonces las expresiones aceptadas por ese sistema de tipos deben evaluarse a un valor del tipo apropiado (en lugar de producir un valor de algún otro tipo no relacionado o provocar un error de tipo). Vijay Saraswat proporciona la siguiente definición relacionada:

Un lenguaje es seguro en cuanto a tipos si las únicas operaciones que se pueden realizar sobre los datos en ese lenguaje son aquellas sancionadas por el tipo de datos. [ 3 ]

Sin embargo, lo que significa precisamente que un programa esté "bien tipado" o "falle" son propiedades de su semántica estática y dinámica , que son específicas de cada lenguaje de programación. En consecuencia, una definición formal y precisa de la solidez de tipos depende del estilo de semántica formal utilizado para especificar un lenguaje. En 1994, Andrew Wright y Matthias Felleisen formularon lo que se ha convertido en la definición estándar y la técnica de prueba para la seguridad de tipos en lenguajes definidos por semántica operacional , [ 4 ] que es la más cercana a la noción de seguridad de tipos tal como la entienden la mayoría de los programadores. Según este enfoque, la semántica de un lenguaje debe tener las dos propiedades siguientes para ser considerada de tipo sólido:

Progreso
Un programa bien tipado nunca se bloquea: cada expresión ya es un valor o puede reducirse a un valor de alguna manera bien definida. En otras palabras, el programa nunca entra en un estado indefinido donde no son posibles más transiciones.
Preservación (o reducción del sujeto )
Después de cada paso de evaluación, el tipo de cada expresión permanece igual (es decir, su tipo se conserva ).

También se han publicado otros tratamientos formales de la solidez de tipos en términos de semántica denotacional y semántica operacional estructural . [ 2 ] [ 5 ] [ 6 ]

Relación con otras formas de seguridad

De forma aislada, la solidez de tipos es una propiedad relativamente débil, ya que esencialmente solo establece que las reglas de un sistema de tipos son internamente consistentes y no pueden ser subvertidas. Sin embargo, en la práctica, los lenguajes de programación están diseñados de manera que la buena tipificación también implica otras propiedades más fuertes, algunas de las cuales incluyen:

  • Prevención de operaciones ilegales. Por ejemplo, un sistema de tipos puede rechazar la expresión 3 / "Hello, World"como inválida, porque el operador de división no está definido para un divisor de cadena .
  • Seguridad de la memoria
    • Los sistemas de tipos pueden evitar punteros no válidos que podrían surgir si un puntero a un tipo de objeto se trata como un puntero a otro tipo.
    • Los sistemas de tipos más sofisticados, como los que admiten tipos dependientes , pueden detectar y rechazar accesos fuera de los límites, evitando posibles desbordamientos de búfer . [ 7 ]
  • Errores lógicos originados en la semántica de diferentes tipos. Por ejemplo, las pulgadas y los milímetros pueden almacenarse como números enteros, pero no deben sustituirse ni sumarse entre sí. Un sistema de tipos puede imponer dos tipos de enteros diferentes para ellos.

Lenguajes con tipado seguro y lenguajes con tipado inseguro

La seguridad de tipos suele ser un requisito para cualquier lenguaje de juguete (es decir, lenguaje esotérico ) propuesto en la investigación académica de lenguajes de programación. Sin embargo, muchos lenguajes son demasiado grandes para las pruebas de seguridad de tipos generadas por humanos, ya que a menudo requieren verificar miles de casos. No obstante, se ha demostrado que algunos lenguajes, como Standard ML , que tiene una semántica rigurosamente definida, cumplen con una definición de seguridad de tipos. [ 8 ] Se cree que otros lenguajes, como Haskell, cumplen con alguna definición de seguridad de tipos, siempre que no se utilicen ciertas características de "escape" (por ejemplo, ` unsafePerformIO` de Haskell , utilizado para "escapar" del entorno restringido habitual en el que es posible la entrada/salida (E/S), elude el sistema de tipos y, por lo tanto, puede usarse para romper la seguridad de tipos. [ 9 ] ) El juego de tipos es otro ejemplo de dicha característica de "escape". Independientemente de las propiedades de la definición del lenguaje, ciertos errores pueden ocurrir en tiempo de ejecución debido a errores en la implementación o en bibliotecas vinculadas escritas en otros lenguajes; tales errores podrían hacer que un tipo de implementación dado no sea seguro en ciertas circunstancias. Una versión temprana de la máquina virtual Java de Sun era vulnerable a este tipo de problema. [ 3 ]

Tipografía fuerte y débil

Los lenguajes de programación se clasifican coloquialmente como fuertemente tipados o débilmente tipados (también llamados de tipado flexible) para referirse a ciertos aspectos de la seguridad de tipos. En 1974, Liskov y Zilles definieron un lenguaje fuertemente tipado como aquel en el que "siempre que un objeto se pasa de una función que llama a una función llamada, su tipo debe ser compatible con el tipo declarado en la función llamada". [ 10 ] En 1977, Jackson escribió: "En un lenguaje fuertemente tipado, cada área de datos tendrá un tipo distinto y cada proceso indicará sus requisitos de comunicación en términos de estos tipos". [ 11 ] Por el contrario, un lenguaje débilmente tipado puede producir resultados impredecibles o realizar una conversión de tipo implícita. [ 12 ]

Gestión de memoria y seguridad de tipos

La seguridad de tipos está estrechamente ligada a la seguridad de la memoria . Por ejemplo, en una implementación de un lenguaje que tiene algún tipot{\displaystyle t}que permite algunos patrones de bits pero no otros, un error de memoria de puntero colgante permite escribir un patrón de bits que no representa un miembro legítimo det{\displaystyle t}en una variable muerta de tipot{\displaystyle t}, lo que provoca un error de tipo al leer la variable. Por el contrario, si el lenguaje es seguro en cuanto a la memoria, no puede permitir que se utilice un entero arbitrario como puntero ; por lo tanto, debe existir un tipo de puntero o referencia independiente.

Como condición mínima, un lenguaje con tipado seguro no debe permitir punteros colgantes entre asignaciones de distintos tipos. Sin embargo, la mayoría de los lenguajes imponen el uso adecuado de los tipos de datos abstractos definidos por los programadores, incluso cuando esto no es estrictamente necesario para la seguridad de la memoria ni para prevenir fallos catastróficos. A las asignaciones se les asigna un tipo que describe su contenido, y este tipo permanece fijo durante toda la asignación. Esto permite que el análisis de alias basado en tipos infiera que las asignaciones de distintos tipos son diferentes.

La mayoría de los lenguajes con tipado seguro utilizan la recolección de basura . Pierce afirma que "es extremadamente difícil lograr la seguridad de tipos en presencia de una operación de desasignación explícita", debido al problema de los punteros colgantes. [ 13 ] Sin embargo, Rust se considera generalmente seguro en cuanto a tipos y utiliza un verificador de préstamos para lograr la seguridad de la memoria, en lugar de la recolección de basura.

Seguridad de tipos en lenguajes orientados a objetos

En los lenguajes orientados a objetos, la seguridad de tipos suele ser intrínseca al hecho de que existe un sistema de tipos . Esto se expresa en términos de definiciones de clases.

Una clase define esencialmente la estructura de los objetos derivados de ella, y una API actúa como un contrato para gestionar dichos objetos. Cada vez que se crea un nuevo objeto, este deberá cumplir con ese contrato.

Cada función que intercambie objetos derivados de una clase específica o que implementen una interfaz específica se adherirá a ese contrato; por lo tanto, en esa función las operaciones permitidas sobre ese objeto serán solo aquellas definidas por los métodos de la clase que implementa el objeto. Esto garantizará que se preserve la integridad del objeto. [ 14 ]

Existen excepciones a esto, como los lenguajes orientados a objetos que permiten la modificación dinámica de la estructura del objeto, o el uso de la reflexión para modificar el contenido de un objeto y superar las restricciones impuestas por las definiciones de los métodos de clase.

Problemas de seguridad de tipos en lenguajes específicos

Ada

Ada se diseñó para ser adecuado para sistemas embebidos , controladores de dispositivos y otras formas de programación de sistemas , pero también para fomentar la programación con tipado seguro. Para resolver estos objetivos contradictorios, Ada limita la inseguridad de tipos a un conjunto específico de construcciones especiales cuyos nombres suelen comenzar con la cadena "Unchecked_" . La desasignación de memoria (Unchecked_Deallocation) puede prohibirse de forma efectiva en una unidad de código Ada aplicando la directiva pragma Pure a dicha unidad. Se espera que los programadores utilicen las construcciones "Unchecked_" con mucha precaución y solo cuando sea necesario; los programas que no las utilizan son con tipado seguro.

El lenguaje de programación SPARK es un subconjunto de Ada que elimina todas sus posibles ambigüedades e inseguridades, al tiempo que añade contratos con comprobación estática a las características del lenguaje. SPARK evita los problemas de los punteros colgantes al prohibir por completo la asignación de memoria en tiempo de ejecución.

Ada2012 añade contratos con comprobación estática al propio lenguaje (en forma de precondiciones y postcondiciones, así como invariantes de tipo).

do

El lenguaje de programación C es seguro en cuanto a tipos en contextos limitados; por ejemplo, se genera un error de compilación cuando se intenta convertir un puntero a un tipo de estructura a un puntero a otro tipo de estructura, a menos que se utilice una conversión explícita. Sin embargo, varias operaciones muy comunes no son seguras en cuanto a tipos; por ejemplo, la forma habitual de imprimir un entero es algo como printf("%d", 12), donde %dindica printfen tiempo de ejecución que espere un argumento entero. (Algo como printf("%s", 12), que indica a la función que espere un puntero a una cadena de caracteres y, sin embargo, proporciona un argumento entero, puede ser aceptado por los compiladores, pero producirá resultados indefinidos). Esto se mitiga parcialmente mediante algunos compiladores (como gcc) que comprueban las correspondencias de tipos entre los argumentos de printf y las cadenas de formato.

Además, C, al igual que Ada, proporciona conversiones explícitas no especificadas o indefinidas; y a diferencia de Ada, los modismos que utilizan estas conversiones son muy comunes y han contribuido a que C tenga una reputación de inseguridad de tipos. Por ejemplo, la forma estándar de asignar memoria en el montón es invocar una función de asignación de memoria, como malloc, con un argumento que indica cuántos bytes se requieren. La función devuelve un puntero void ( void*), que el código que la llama debe convertir explícita o implícitamente al tipo de puntero apropiado. Las implementaciones de C anteriores a la estandarización requerían una conversión explícita para hacerlo, por lo que para una asignación de algún struct Foo, el código se convirtió en la práctica aceptada. [ 15 ] devuelve que no necesita ser convertido explícitamente en C, pero en C++ esta conversión es obligatoria para la seguridad de tipos.Foo* foo = (struct Foo*)malloc(sizeof(struct Foo))malloc()void*

C++

C++ es generalmente más seguro en cuanto a tipos que su predecesor, C, con características como no permitir la conversión implícita de void*a otros tipos de puntero [ 16 ] y otras características como:

  • El nuevo operador devuelve un puntero de un tipo basado en el operando, mientras que malloc devuelve un puntero void.
  • El código C++ puede utilizar funciones virtuales y plantillas para lograr un polimorfismo seguro en cuanto a tipos, sin necesidad de punteros void.
  • Operadores de conversión más seguros, como dynamic_castlos que realizan comprobaciones de tipo en tiempo de ejecución entre punteros y referencias; mientras que static_castrealizan comprobaciones en tiempo de compilación entre tipos que se van a convertir uno a otro, lo que generalmente es más seguro que las conversiones al estilo C.
  • Las enumeraciones fuertemente tipadas de C++11 (también conocidas como enum class'es') no se pueden convertir implícitamente a enteros u otros tipos de enumeración, ni viceversa.
  • Los constructores explícitos de C++ y los operadores de conversión explícita de C++11 impiden las conversiones de tipo implícitas.

DO#

C# es seguro en cuanto a tipos. Admite punteros sin tipo, pero se debe acceder a ellos mediante la palabra clave `unsafe`, que puede prohibirse a nivel del compilador. Ofrece soporte inherente para la validación de conversiones en tiempo de ejecución. Las conversiones se pueden validar mediante la palabra clave `as`, que devuelve una referencia nula si la conversión no es válida, o mediante una conversión al estilo de C, que lanza una excepción si la conversión no es válida. Consulte Operadores de conversión de C# .

Depender excesivamente del tipo de objeto (del cual se derivan todos los demás tipos) conlleva el riesgo de frustrar el propósito del sistema de tipos de C#. Generalmente, es mejor práctica abandonar las referencias a objetos en favor de los genéricos , de forma similar a las plantillas en C++ y los genéricos en Java .

Java

El lenguaje Java está diseñado para garantizar la seguridad de tipos. Todo en Java ocurre dentro de un objeto y cada objeto es una instancia de una clase .

Para implementar la seguridad de tipos , cada objeto debe asignarse antes de su uso . Java permite el uso de tipos primitivos , pero solo dentro de objetos debidamente asignados.

En ocasiones, parte de la seguridad de tipos se implementa indirectamente: por ejemplo, la clase BigDecimal representa un número de coma flotante de precisión arbitraria, pero solo maneja números que pueden expresarse con una representación finita. La operación BigDecimal.divide() calcula un nuevo objeto como la división de dos números expresados ​​como BigDecimal.

En este caso, si la división no tiene una representación finita, como cuando se calcula, por ejemplo, 1/3 = 0,33333..., el método divide() puede generar una excepción si no se ha definido ningún modo de redondeo para la operación. Por lo tanto, la biblioteca, y no el lenguaje, garantiza que el objeto respete el contrato implícito en la definición de la clase.

ML estándar

Standard ML tiene una semántica rigurosamente definida y se sabe que es seguro en cuanto a tipos. Sin embargo, algunas implementaciones, como Standard ML of New Jersey (SML/NJ), su variante sintáctica Mythryl y MLton , proporcionan bibliotecas que ofrecen operaciones no seguras. Estas funcionalidades se suelen usar junto con las interfaces de funciones externas de dichas implementaciones para interactuar con código que no es ML (como bibliotecas de C) que puede requerir datos organizados de maneras específicas. Otro ejemplo es el propio nivel superior interactivo de SML/NJ , que debe usar operaciones no seguras para ejecutar el código ML introducido por el usuario.

Módulo-2

Modula-2 es un lenguaje fuertemente tipado con una filosofía de diseño que exige que cualquier funcionalidad insegura se marque explícitamente como tal. Esto se logra "moviendo" dichas funcionalidades a una pseudobiblioteca integrada llamada SYSTEM, desde donde deben importarse antes de poder usarse. La importación hace visible cuándo se utilizan dichas funcionalidades. Desafortunadamente, esto no se implementó en consecuencia en el informe original del lenguaje y su implementación. [ 17 ] Todavía quedaban funcionalidades inseguras, como la sintaxis de conversión de tipos y los registros de variantes (heredados de Pascal), que podían usarse sin importación previa. [ 18 ] La dificultad de mover estas funcionalidades al pseudomódulo SYSTEM radicaba en la falta de un identificador para la funcionalidad que pudiera importarse, ya que solo se pueden importar identificadores, pero no sintaxis.

SISTEMA DE IMPORTACIÓN ; ( * permite el uso de ciertas instalaciones no seguras: *) VAR palabra : SISTEMA . PALABRA ; dirección : SISTEMA.DIRECCIÓN ; dirección : = SISTEMA.DIRECCIÓN ( palabra ) ;(* pero la sintaxis de conversión de tipos se puede usar sin dicha importación *) VAR i : INTEGER ; n : CARDINAL ; n := CARDINAL ( i ); (* o *) i := INTEGER ( n );

El estándar ISO Modula-2 corrigió esto para la función de conversión de tipos cambiando la sintaxis de conversión de tipos a una función llamada CAST que debe importarse del pseudomódulo SYSTEM. Sin embargo, otras funciones no seguras, como los registros de variantes, permanecieron disponibles sin ninguna importación del pseudomódulo SYSTEM. [ 19 ]

IMPORT SYSTEM ; VAR i : INTEGER ; n : CARDINAL ; i := SYSTEM.CAST ( INTEGER , n ) ; ( * Conversión de tipo en ISO Modula-2 *)

Una revisión reciente del lenguaje aplicó rigurosamente la filosofía de diseño original. Primero, el pseudomódulo SYSTEM pasó a llamarse UNSAFE para hacer más explícita la naturaleza insegura de las funcionalidades importadas desde allí. Luego, todas las funcionalidades inseguras restantes se eliminaron por completo (por ejemplo, los registros de variantes) o se trasladaron al pseudomódulo UNSAFE. Para las funcionalidades que no tienen un identificador que se pueda importar, se introdujeron identificadores de habilitación. Para habilitar una funcionalidad de este tipo, su identificador de habilitación correspondiente debe importarse del pseudomódulo UNSAFE. Ya no quedan funcionalidades inseguras en el lenguaje que no requieran la importación desde UNSAFE. [ 18 ]

IMPORTAR INSEGURO ; VAR i : ENTERO ; n : CARDINAL ; i := INSEGURO.CAST ( ENTERO , n ) ; (* Conversión de tipo en Modula-2 Revisión 2010 *)FROM UNSAFE IMPORT FFI ; (* identificador habilitador para la facilidad de interfaz de función externa *) <*FFI="C"*> (* pragma para la interfaz de función externa a C *)

Pascal

Pascal ha tenido varios requisitos de seguridad de tipos, algunos de los cuales se mantienen en ciertos compiladores. Cuando un compilador de Pascal exige "tipado estricto", dos variables no pueden asignarse entre sí a menos que sean compatibles (como la conversión de entero a real) o se les asigne el mismo subtipo. Por ejemplo, si tiene el siguiente fragmento de código:

tipo DosTipos = registro I : Entero ; Q : Real ; fin ;DualTypes = registro I : Entero ; Q : Real ; fin ;var T1 , T2 : TwoTypes ; D1 , D2 : DualTypes ;

Bajo tipado estricto, una variable definida como TwoTypes no es compatible con DualTypes (porque no son idénticas, aunque los componentes de ese tipo definido por el usuario sean idénticos) y una asignación de es ilegal. Una asignación de sería legal porque los subtipos a los que se definen son idénticos. Sin embargo, una asignación como sería legal.T1 := D2;T1 := T2;T1.Q := D1.Q;

Lisp común

En general, Common Lisp es un lenguaje con tipado seguro. Un compilador de Common Lisp se encarga de insertar comprobaciones dinámicas para las operaciones cuya seguridad de tipos no puede demostrarse estáticamente. Sin embargo, un programador puede indicar que un programa debe compilarse con un nivel inferior de comprobación dinámica de tipos. [ 20 ] Un programa compilado en tal modo no puede considerarse con tipado seguro.

Ejemplos de C++

Los siguientes ejemplos ilustran cómo los operadores de conversión de tipos de C++ pueden comprometer la seguridad de tipos cuando se usan incorrectamente. El primer ejemplo muestra cómo se pueden convertir incorrectamente tipos de datos básicos:

#include <iostream> using namespace std ;int main () { int ival = 5 ; // valor entero float fval = reinterpret_cast < float &> ( ival ); // reinterpretar patrón de bits cout << fval << endl ; // imprimir entero como float return 0 ; }

En este ejemplo, reinterpret_castse impide explícitamente que el compilador realice una conversión segura de entero a valor de punto flotante. [ 21 ] Cuando se ejecuta el programa, generará un valor de punto flotante basura. El problema podría haberse evitado escribiendo en su lugarfloat fval = ival;

El siguiente ejemplo muestra cómo se pueden convertir incorrectamente las referencias a objetos:

#include <iostream> using namespace std ;clase Padre { público : virtual ~ Padre () {} // destructor virtual para RTTI };clase Child1 : público Parent { público : int a ; };clase Child2 : público Parent { público : float b ; };int main () { Child1 c1 ; c1.a = 5 ; Parent & p = c1 ; // la conversión ascendente siempre es segura Child2 & c2 = static_cast < Child2 & > ( p ); // la conversión descendente no es válida cout << c2.b << endl ; // generará datos basura return 0 ; }

Las dos clases hijas tienen miembros de tipos diferentes. Al convertir un puntero de la clase padre a un puntero de la clase hija, el puntero resultante puede no apuntar a un objeto válido del tipo correcto. En el ejemplo, esto provoca que se imprima un valor basura. El problema podría haberse evitado reemplazando static_castcon dynamic_castuna función que lanza una excepción en caso de conversiones no válidas. [ 22 ]

Véase también

Notas

  1. "Qué debes saber antes de debatir sobre sistemas de tipos | Ovid [ blogs.perl.org ] " . blogs.perl.org . Consultado el 27 de junio de 2023 .
  2. 1 2 Milner, Robin (1978), "Una teoría del polimorfismo de tipos en programación", Journal of Computer and System Sciences , 17 (3): 348– 375, doi : 10.1016/0022-0000(78)90014-4 , hdl : 20.500.11820/d16745d7-f113-44f0-a7a3-687c2b709f66
  3. 12Saraswat, Vijay (1997-08-15). "Java is not type-safe". Retrieved 2008-10-08.
  4. Wright, A. K.; Felleisen, M. (15 November 1994). "A Syntactic Approach to Type Soundness". Information and Computation. 115 (1): 38–94. doi:10.1006/inco.1994.1093. ISSN 0890-5401.
  5. Damas, Luis; Milner, Robin (25 January 1982). "Principal type-schemes for functional programs". Proceedings of the 9th ACM SIGPLAN-SIGACT symposium on Principles of programming languages - POPL '82. Association for Computing Machinery. pp. 207–212. doi:10.1145/582153.582176. ISBN 0897910656. S2CID 11319320.
  6. Tofte, Mads (1988). Operational Semantics and Polymorphic Type Inference (Thesis).
  7. Henriksen, Troels; Elsman, Martin (17 June 2021). "Towards size-dependent types for array programming". Proceedings of the 7th ACM SIGPLAN International Workshop on Libraries, Languages and Compilers for Array Programming. Association for Computing Machinery. pp. 1–14. doi:10.1145/3460944.3464310. ISBN 9781450384667. S2CID 235474098.
  8. Standard ML. Smlnj.org. Retrieved on 2013-11-02.
  9. "System.IO.Unsafe". GHC libraries manual: base-3.0.1.0. Archived from the original on 2008-07-05. Retrieved 2008-07-17.
  10. Liskov, B; Zilles, S (1974). "Programming with abstract data types". ACM SIGPLAN Notices. 9 (4): 50–59. CiteSeerX 10.1.1.136.3043. doi:10.1145/942572.807045.
  11. Jackson, K. (1977). "Parallel processing and modular software construction". Design and Implementation of Programming Languages. Lecture Notes in Computer Science. Vol. 54. pp. 436–443. doi:10.1007/BFb0021435. ISBN 3-540-08360-X.
  12. "CS1130. Transition to OO programming. – Spring 2012 --self-paced version". Cornell University, Department of Computer Science. 2005. Retrieved 2023-09-15.
  13. Pierce, Benjamin C. (2002). Tipos y lenguajes de programación . Cambridge, Mass.: MIT Press. pág. 158. ISBN  0-262-16209-1.
  14. Por lo tanto, la seguridad de tipos también es una cuestión de buena definición de clase: los métodos públicos que modifican el estado interno de un objeto deben preservar la integridad del objeto.
  15. Kernighan ; Dennis M. Ritchie (marzo de 1988). El lenguaje de programación C (2.ª ed.). Englewood Cliffs, NJ : Prentice Hall . pág. 142. ISBN   978-0-13-110362-7En C , el método adecuado es declarar que mallocdevuelve un puntero a void, y luego convertir explícitamente el puntero al tipo deseado con una conversión.
  16. "Centro de conocimiento de IBM" . ibm.com .
  17. Niklaus Wirth (1985). Programación en Modula-2 . Springer Verlag.
  18. 1 2 "La separación de instalaciones seguras e inseguras" . Consultado el 24 de marzo de 2015 .
  19. «Referencia del lenguaje ISO Modula-2» . Consultado el 24 de marzo de 2015 .
  20. "HyperSpec de Common Lisp" . Consultado el 26 de mayo de 2013 .
  21. "reinterpret_cast conversion - cppreference.com" . En.cppreference.com . Consultado el 21/09/2022 .
  22. "conversión dynamic_cast - cppreference.com" . En.cppreference.com . Consultado el 21/09/2022 .

Referencias

  • Pierce, Benjamin C. (2002). Tipos y lenguajes de programación . MIT Press. ISBN 978-0-262-16209-8.
  • "Type Safe" . Wiki del repositorio de patrones de Portland .
  • Wright, Andrew K.; Matthias Felleisen (1994). "Un enfoque sintáctico para la solidez de tipos" . Information and Computation . 115 (1): 38– 94. doi : 10.1006/inco.1994.1093 .
  • Macrakis, Stavros (abril de 1982). "Seguridad y potencia". ACM SIGSOFT Software Engineering Notes . 7 (2): 25– 26. doi : 10.1145/1005937.1005941 . S2CID 10426644 .