Simulador EGEL Ingeniería de Software

💻 Lenguajes de desarrollo de software

Lenguajes de desarrollo de software

La selección de un lenguaje depende de tres ejes técnicos —tipado, ejecución y gestión de memoria— y de los requisitos del escenario. El tipado estático verifica los tipos en tiempo de compilación, antes de ejecutar el programa (C, C++, Java, C# y Rust); el tipado dinámico los verifica en tiempo de ejecución (Python, JavaScript, Ruby y PHP). Este eje es ortogonal al de la fuerza: el tipado fuerte no permite operaciones entre tipos incompatibles sin conversión explícita y reporta siempre los errores de tipo, mientras que el tipado débil admite coerciones implícitas que pueden ocultar errores. Existen así las cuatro combinaciones: estático-fuerte (Java), estático-débil (C), dinámico-fuerte (Python) y dinámico-débil (JavaScript).

En cuanto a la ejecución, los lenguajes compilados traducen el código fuente a código máquina antes de correr, con mayor rendimiento; los interpretados traducen y ejecutan instrucción por instrucción en tiempo de ejecución, con mayor portabilidad y flexibilidad pero menor velocidad. Muchos usan bytecode intermedio: Java compila a bytecode (.class) que ejecuta la JVM (portabilidad, write once run anywhere); CPython compila a bytecode (.pyc) que interpreta la PVM.

Excepciones y traza: ante un error, el lenguaje lanza una excepción que se captura y trata (por ejemplo con try/catch), preservando la seguridad de la ejecución. Para trazar un código dado, sigue el flujo línea por línea anotando el valor de cada variable, recordando que en tipado dinámico una misma variable puede cambiar de tipo. Al seleccionar el lenguaje, contrasta los requisitos: rendimiento nativo y control de memoria favorecen a C, C++ o Rust; portabilidad y productividad favorecen a Java, C# o lenguajes dinámicos como Python.

Practica el banco completo y haz simulacros gratis

Preguntas de muestra (35)

1. En el diseño de lenguajes de programación, ¿en qué momento se realiza la verificación de tipos cuando un lenguaje utiliza tipado estático?

  1. En tiempo de ejecución, mientras el programa corre
  2. Durante el enlazado del código objeto final
  3. En tiempo de compilación, antes de ejecutar el programa
  4. Durante la recolección automática de basura

El tipado estático verifica los tipos en tiempo de compilación, antes de que el programa se ejecute, como en C, C++, Java, C# y Rust; el enlazado y la recolección de basura son procesos distintos que no verifican tipos. (Sebesta, Concepts of Programming Languages, cap. 6; Pierce, Types and Programming Languages, cap. 1)

2. ¿En qué momento realiza la verificación de tipos un lenguaje de tipado dinámico, como Python o JavaScript?

  1. En tiempo de ejecución, conforme el programa corre
  2. En tiempo de compilación, antes de generar el ejecutable
  3. En tiempo de enlazado, al combinar los módulos
  4. En tiempo de diseño, al declarar las variables

Python, JavaScript, Ruby y PHP verifican los tipos en tiempo de ejecución, a diferencia del tipado estático, que verifica en compilación. (Sebesta, Concepts of Programming Languages, cap. 5-6; Scott, Programming Language Pragmatics, cap. 7)

3. ¿Qué característica define a un lenguaje fuertemente tipado (strong typing)?

  1. Permite convertir automáticamente cualquier tipo en otro sin restricciones
  2. Determina el tipo de una variable únicamente al momento de compilarla
  3. Omite la verificación de tipos para mejorar el rendimiento de ejecución
  4. Impide realizar operaciones entre tipos incompatibles sin una conversión explícita

El tipado fuerte evita que se apliquen operaciones a tipos incompatibles sin conversión explícita; verificar el tipo 'al compilar' describe el eje estático/dinámico, que es independiente de fuerte/débil. (Sebesta, Concepts of Programming Languages, cap. 6, sección 'Strong Typing')

4. ¿Qué caracteriza al tipado débil (weak typing) de un lenguaje de programación?

  1. Exige declarar explícitamente el tipo de cada variable antes de usarla
  2. Permite coerciones o conversiones implícitas entre tipos distintos
  3. Verifica los tipos exclusivamente en tiempo de compilación
  4. Prohíbe cualquier conversión automática entre tipos numéricos y cadenas

El tipado débil permite conversiones implícitas que pueden ocultar errores, como ocurre en C y JavaScript; prohibir toda conversión automática describiría, en cambio, un tipado fuerte. (Sebesta, Concepts of Programming Languages, cap. 6; ECMA-262 (ECMAScript), sección Type Conversion)

5. Un equipo de desarrollo analiza un lenguaje que verifica los tipos de las variables antes de ejecutar el programa, pero que permite sumar directamente un carácter con un entero sin exigir una conversión explícita. ¿Cómo se clasifica este lenguaje según los dos ejes de tipado?

  1. Estático y débil
  2. Estático y fuerte
  3. Dinámico y débil
  4. Dinámico y fuerte

Verificar tipos antes de ejecutar corresponde al eje estático, y permitir sumar un char con un int sin conversión explícita corresponde al eje débil; C es el ejemplo típico de esta combinación. (Scott, Programming Language Pragmatics, cap. 7 (Type Systems); ISO/IEC 9899, cláusulas 6.2-6.3)

6. ¿Qué sucede con el código fuente de un programa escrito en Java antes de que pueda ejecutarse?

  1. Se interpreta línea por línea directamente por el sistema operativo
  2. Se compila a bytecode que después ejecuta la Máquina Virtual de Java (JVM)
  3. Se traduce a código máquina nativo del procesador de forma directa
  4. Se transforma en un script que corre sobre un navegador web

Java compila el código fuente a bytecode (.class) que ejecuta la JVM, lo que le da portabilidad ('write once, run anywhere'); a diferencia de C, no se traduce directamente a código máquina nativo. (The Java Language Specification, cap. 4; The Java Virtual Machine Specification)

7. Una desarrolladora utiliza CPython, la implementación de referencia de Python, para ejecutar su programa. ¿Qué describe correctamente lo que ocurre internamente antes de que las instrucciones se ejecuten?

  1. El código fuente se traduce directamente a código máquina del procesador, sin pasos intermedios
  2. El código fuente se ejecuta símbolo por símbolo sin ninguna fase previa de traducción
  3. El código fuente se compila a bytecode (.pyc), que interpreta la máquina virtual de Python
  4. El código fuente se compila a un ejecutable nativo enlazado estáticamente

CPython compila el código fuente a bytecode (.pyc) que después interpreta la máquina virtual de Python (PVM), sin traducirlo directamente a código máquina nativo. (The Python Language Reference (docs.python.org), sección Execution model)

8. ¿Cuál de las siguientes combinaciones describe correctamente las características del lenguaje C?

  1. Tipado dinámico y fuerte, interpretado, con recolección automática de basura
  2. Tipado estático y fuerte, compilado a bytecode, con gestión manual de memoria
  3. Tipado dinámico y débil, compilado a código máquina nativo, sin apuntadores
  4. Tipado estático y débil, compilado a código máquina nativo, con gestión manual de memoria

C es de tipado estático (verifica en compilación) y débil (permite coerciones implícitas), se compila a código máquina nativo y requiere manejo manual de memoria con malloc/free, sin recolector de basura. (ISO/IEC 9899 (Programming languages - C), cláusulas 6.2 y 6.3)

9. ¿Cuál de los siguientes lenguajes NO utiliza recolección automática de basura (garbage collection) para administrar su memoria?

  1. Java
  2. C++
  3. Python
  4. Go

C++ requiere gestión manual de memoria, igual que C; Java, Python y Go incorporan recolección automática de basura para reducir fugas de memoria. (Sebesta, Concepts of Programming Languages, cap. 6.11 (Pointer and Reference Types / heap management))

10. Un equipo debe elegir la estrategia de traducción de un lenguaje para desarrollar un sistema donde el rendimiento en tiempo de ejecución es la prioridad principal, aceptando un mayor tiempo previo de preparación. ¿Qué estrategia conviene según las características de traducción de los lenguajes?

  1. Traducir el código fuente completo a código máquina antes de ejecutarlo (compilación)
  2. Traducir y ejecutar cada instrucción una por una durante la ejecución (interpretación)
  3. Ejecutar el código fuente sin ninguna fase de traducción previa
  4. Traducir el código a bytecode y omitir cualquier optimización posterior

Los lenguajes compilados traducen el código fuente completo a código máquina antes de ejecutarlo, lo que ofrece mayor rendimiento en ejecución a cambio de un proceso previo de compilación; los interpretados priorizan portabilidad sobre velocidad. (Aho et al., Compilers: Principles, Techniques and Tools, cap. 1)

11. ¿Qué algoritmo permite que un lenguaje de tipado estático, como ML o Haskell, deduzca automáticamente el tipo de una variable sin que el programador lo declare explícitamente?

  1. El algoritmo de recolección de basura por marcado y barrido
  2. El algoritmo de resolución de nombres por ámbito léxico
  3. El algoritmo de inferencia de tipos Hindley-Milner
  4. El algoritmo de análisis sintáctico ascendente LALR

El algoritmo Hindley-Milner es el mecanismo clásico de inferencia de tipos usado en lenguajes como ML y Haskell, y permite mantener el tipado estático sin declaración explícita de tipos. (Pierce, Types and Programming Languages, cap. 22 (Type Reconstruction))

12. En Python, una función recibe un objeto y le invoca el método volar() sin comprobar antes de qué clase proviene dicho objeto; la función funciona correctamente con cualquier objeto que tenga ese método implementado. ¿Qué característica del tipado dinámico ilustra este comportamiento?

  1. Duck typing: la aptitud del objeto se determina por sus métodos disponibles, no por su clase declarada
  2. Tipado nominal: la aptitud del objeto depende del nombre exacto de su clase
  3. Inferencia de tipos: el intérprete deduce el tipo exacto antes de ejecutar la llamada
  4. Tipado fuerte estricto: el objeto debe heredar de una clase base común

El 'duck typing' es propio de lenguajes dinámicos como Python: la aptitud de un objeto para una operación depende de que posea los métodos requeridos, no de su clase declarada ni de una jerarquía de herencia. (The Python Language Reference / Python Glossary (docs.python.org), término 'duck-typing')

13. ¿Qué garantiza un sistema de tipos que cumple la propiedad de seguridad de tipos (type safety)?

  1. Que todas las variables se declaren obligatoriamente con tipado estático
  2. Que el programa se ejecute más rápido al eliminar la verificación de tipos
  3. Que el recolector de basura libere automáticamente toda la memoria utilizada
  4. Que no ocurran comportamientos indefinidos por errores de tipo no detectados durante la ejecución

La seguridad de tipos (type safety) garantiza la ausencia de comportamientos indefinidos por errores de tipo no detectados en ejecución; esta propiedad es independiente de que el tipado sea estático o dinámico. (Pierce, Types and Programming Languages, cap. 8 (teorema de soundness: progreso + preservación))

14. Un equipo requiere un lenguaje de tipado estático y fuerte que garantice la seguridad de memoria en tiempo de compilación, sin depender de un recolector de basura en tiempo de ejecución. ¿Qué mecanismo de un lenguaje como Rust cumple este requerimiento?

  1. La recolección de basura generacional ejecutada en segundo plano
  2. El sistema de propiedad (ownership) y préstamos (borrowing) verificado en la compilación
  3. La conversión implícita automática entre tipos numéricos y apuntadores
  4. La interpretación línea por línea del código fuente en tiempo de ejecución

Rust garantiza la seguridad de memoria en tiempo de compilación mediante su sistema de ownership y borrowing, sin necesidad de un recolector de basura en tiempo de ejecución. (The Rust Programming Language (doc.rust-lang.org), cap. 4 'Understanding Ownership')

15. En Java, dos tipos se consideran compatibles solo si comparten el mismo nombre de clase o una relación de herencia declarada explícitamente. ¿Qué modelo de equivalencia de tipos ejemplifica este comportamiento?

  1. Tipado nominal, en el que la compatibilidad se basa en el nombre o la declaración explícita del tipo
  2. Tipado estructural, en el que la compatibilidad se basa en la forma o los miembros del tipo
  3. Tipado dinámico, en el que la compatibilidad se determina en tiempo de ejecución
  4. Tipado débil, en el que la compatibilidad se determina por coerciones implícitas

En el tipado nominal (Java, C++) la compatibilidad de tipos depende del nombre o la declaración explícita, a diferencia del tipado estructural (OCaml, TypeScript), donde depende de la forma del tipo. (Scott, Programming Language Pragmatics, cap. 7 (Type Equivalence: name vs structural))

16. ¿Cuáles son los tres pilares fundamentales que caracterizan al paradigma de programación orientado a objetos?

  1. Recursión, inmutabilidad y funciones puras
  2. Concurrencia, paralelismo y sincronización
  3. Compilación, interpretación y enlazado dinámico
  4. Encapsulamiento, herencia y polimorfismo

El paradigma orientado a objetos, presente en lenguajes como Java, se caracteriza por el encapsulamiento, la herencia y el polimorfismo; la recursión y la inmutabilidad son propias del paradigma funcional. (Sebesta, Concepts of Programming Languages, cap. sobre Object-Oriented Programming)

17. ¿Qué característica distingue principalmente al paradigma de programación funcional, presente en lenguajes como Haskell?

  1. El uso de funciones puras que evitan modificar estado y efectos colaterales
  2. La organización del código en clases que encapsulan atributos y métodos
  3. La ejecución secuencial de instrucciones que modifican variables globales
  4. La declaración de reglas y hechos que un motor de inferencia resuelve

El paradigma funcional se basa en funciones puras, sin efectos colaterales, e inmutabilidad de los datos, como ocurre en Haskell; declarar reglas y hechos corresponde, en cambio, al paradigma lógico. (Sebesta, Concepts of Programming Languages, cap. 'Functional Programming Languages')

18. Un lenguaje describe la solución de un problema mediante una secuencia explícita de instrucciones que modifican el estado de variables paso a paso, como ocurre en C. ¿A qué paradigma de programación corresponde este enfoque?

  1. Paradigma orientado a objetos
  2. Paradigma imperativo (procedural)
  3. Paradigma funcional
  4. Paradigma declarativo lógico

El paradigma imperativo (procedural), ejemplificado por C, describe la solución mediante una secuencia de instrucciones que modifican el estado del programa; el paradigma orientado a objetos organiza además ese estado en objetos con comportamiento propio. (Sebesta, Concepts of Programming Languages, cap. sobre Imperative Programming Languages)

19. Un equipo necesita consultar y transformar información de una base de datos relacional describiendo qué resultado desea obtener, sin especificar el algoritmo paso a paso para calcularlo, como ocurre al escribir una consulta SQL. ¿Qué paradigma de programación ejemplifica mejor este enfoque?

  1. Paradigma imperativo
  2. Paradigma orientado a objetos
  3. Paradigma declarativo
  4. Paradigma concurrente

El paradigma declarativo describe el 'qué' se desea obtener en lugar del 'cómo' obtenerlo paso a paso, como en una consulta SQL; el paradigma imperativo, en cambio, exige especificar la secuencia de instrucciones. (Sebesta, Concepts of Programming Languages, cap. sobre Logic Programming Languages / programación declarativa)

20. Un lenguaje permite definir clases con herencia y polimorfismo, además de tratar funciones como valores de primera clase que pueden pasarse como argumento, sin restringir al programador a un único estilo de solución. ¿Cómo se clasifica un lenguaje con estas características?

  1. Lenguaje multiparadigma
  2. Lenguaje puramente funcional
  3. Lenguaje puramente orientado a objetos
  4. Lenguaje puramente declarativo

Un lenguaje multiparadigma, como Python, Rust o C++, combina elementos de distintos paradigmas, por ejemplo orientado a objetos y funcional, sin restringir al programador a un único estilo de solución. (Sebesta, Concepts of Programming Languages, cap. introductorio sobre paradigmas de programación)

21. ¿Qué elementos utiliza principalmente el paradigma de programación lógica, ejemplificado por Prolog, para resolver un problema?

  1. Clases y objetos que encapsulan datos y comportamiento
  2. Funciones puras que se componen para transformar datos
  3. Instrucciones secuenciales que modifican variables de estado
  4. Hechos y reglas que un motor de inferencia resuelve mediante resolución lógica

El paradigma lógico, ejemplificado por Prolog, se basa en declarar hechos y reglas que un motor de inferencia resuelve mediante resolución lógica, a diferencia del paradigma imperativo, que ejecuta instrucciones secuenciales. (Sebesta, Concepts of Programming Languages, cap. 'Logic Programming Languages')

22. Dado el siguiente fragmento de código en JavaScript: var resultado = "5" + 3; console.log(resultado); ¿Qué imprime este código y qué caracteriza este comportamiento?

  1. Imprime 8 porque el operador + convierte la cadena en un número antes de sumar
  2. Imprime "53" porque el operador + concatena al convertir el número en cadena por coerción implícita
  3. Genera un error de tipos porque JavaScript no permite mezclar cadenas y números
  4. Imprime 53 como número porque JavaScript convierte automáticamente la cadena "5" en entero

JavaScript es de tipado débil: al usar + con una cadena y un número, convierte el número en cadena y concatena, produciendo "53" como cadena; el operador + no fuerza aquí una conversión a número. (ECMA-262 (ECMAScript), sección Type Conversion / Abstract Operations)

23. Dado el siguiente fragmento de código en Python: resultado = "5" + 3 print(resultado) ¿Qué ocurre al ejecutar este código?

  1. Se imprime "53" porque Python concatena automáticamente cadenas y números como JavaScript
  2. Se imprime 8 porque Python convierte automáticamente la cadena en entero antes de sumar
  3. Se genera un TypeError en tiempo de ejecución porque Python no convierte implícitamente entre cadena y entero
  4. Se genera un error de compilación porque Python detecta el conflicto de tipos antes de ejecutar

Python es de tipado fuerte, aunque dinámico: no permite operar entre str e int sin conversión explícita, por lo que arroja un TypeError en tiempo de ejecución, ya que al ser interpretado el error surge al ejecutar, no al compilar. (The Python Language Reference, sección Data model; Sebesta, cap. 6, 'Strong Typing')

24. Dado el siguiente fragmento de código en C: char letra = 'A'; int numero = letra + 1; printf("%d", numero); ¿Qué imprime este programa?

  1. A1, porque C concatena el carácter con el número como una cadena
  2. Un error de compilación, porque C no permite sumar un char con un int
  3. 65, porque C ignora la suma y solo imprime el valor original del carácter
  4. 66, porque C convierte implícitamente el carácter en su valor entero antes de sumar

'A' equivale al valor entero 65 en el código ASCII; al ser C un lenguaje de tipado débil, convierte implícitamente el char en int, por lo que la suma 65+1 resulta en 66. (ISO/IEC 9899 (Programming languages - C), cláusula 6.3 (Conversions))

25. Dado el siguiente fragmento de código en C++: auto contador = 10; contador = "texto"; ¿Qué ocurre al intentar compilar este código?

  1. Ocurre un error de compilación, porque auto fija el tipo entero en tiempo de compilación y no admite asignar una cadena
  2. El programa compila y ejecuta correctamente, porque auto permite cambiar el tipo de la variable en cualquier momento
  3. El programa compila, pero produce un error de tipos hasta el momento de ejecutarlo
  4. Ocurre un error de compilación, porque la palabra clave auto no existe en C++11

auto, incorporado en C++11, infiere el tipo en tiempo de compilación a partir del valor inicial, pero el lenguaje sigue siendo de tipado estático: una vez fijado el tipo entero, no puede reasignarse una cadena. (ISO/IEC 14882 (C++11), especificación de la palabra clave auto)

26. Dado el siguiente fragmento de código en Rust: let s1 = String::from("hola"); let s2 = s1; println!("{}", s1); ¿Qué ocurre al intentar compilar este código?

  1. El programa compila y muestra "hola", porque Rust copia automáticamente el contenido de s1 en s2
  2. Ocurre un error de compilación, porque la propiedad del valor se transfirió de s1 a s2 y s1 ya no es válida
  3. El programa compila, pero falla en tiempo de ejecución al intentar leer una variable movida
  4. El programa compila y muestra una cadena vacía, porque s1 queda reiniciada tras la asignación

El sistema de ownership de Rust transfiere la propiedad del valor de s1 a s2; usar s1 después de ese movimiento es un error detectado en tiempo de compilación, no en ejecución. (The Rust Programming Language (doc.rust-lang.org), cap. 4 'Understanding Ownership')

27. Un programa se traduce por completo a lenguaje máquina antes de ejecutarse, generando un archivo ejecutable independiente del código fuente original. ¿Qué modelo de traducción de lenguajes describe este proceso?

  1. Interpretación
  2. Compilación
  3. Ligado dinámico
  4. Tipado estructural

La compilación traduce todo el código fuente a código máquina antes de la ejecución, a diferencia de la interpretación, que traduce y ejecuta instrucción por instrucción. (A. V. Aho et al., Compilers: Principles, Techniques and Tools, cap. 1)

28. En un lenguaje interpretado, ¿en qué momento se traduce y ejecuta cada instrucción del programa?

  1. Únicamente al momento de instalar el entorno de ejecución
  2. Todo el programa de una sola vez, antes de ejecutarse
  3. Instrucción por instrucción, en tiempo de ejecución
  4. Solo cuando el programador solicita depuración

En la interpretación, cada instrucción se traduce y ejecuta en tiempo de ejecución, a diferencia de la compilación, que traduce todo el programa previamente. (A. V. Aho et al., Compilers: Principles, Techniques and Tools, cap. 1)

29. Un equipo de desarrollo necesita máximo rendimiento en tiempo de ejecución para un sistema embebido con recursos muy limitados, y puede aceptar un mayor tiempo de traducción previo a la ejecución. ¿Qué modelo de ejecución conviene priorizar?

  1. Compilación a código máquina nativo
  2. Interpretación del código fuente instrucción por instrucción
  3. Ejecución de bytecode intermedio sobre una máquina virtual
  4. Compilación en tiempo de ejecución (JIT) sobre una máquina virtual

La compilación anticipada a código máquina nativo ofrece el mayor rendimiento en ejecución y el menor consumo de recursos; la interpretación y los modelos con máquina virtual añaden sobrecarga en tiempo de ejecución. (A. V. Aho et al., Compilers: Principles, Techniques and Tools, cap. 1)

30. Un equipo prioriza poder ejecutar su aplicación en múltiples plataformas sin recompilar el código para cada una, aceptando a cambio una menor velocidad de ejecución. ¿Qué modelo de traducción resulta más adecuado para este requerimiento?

  1. Compilación a código máquina nativo del procesador
  2. Interpretación del código fuente
  3. Compilación anticipada (AOT) a un ejecutable propio de cada plataforma
  4. Ensamblado directo a instrucciones específicas del procesador

Los lenguajes interpretados ejecutan el mismo código fuente en cualquier plataforma que tenga el intérprete, ofreciendo portabilidad a costa de velocidad; las demás opciones generan código nativo dependiente de la plataforma y exigen recompilar. (A. V. Aho et al., Compilers: Principles, Techniques and Tools, cap. 1)

31. Un programador compila un archivo fuente de Java y obtiene un archivo con extensión .class, el cual después ejecuta sin recompilar en distintos sistemas operativos. ¿Qué componente hace posible esta portabilidad?

  1. El compilador nativo que genera un ejecutable distinto para cada sistema operativo
  2. El sistema operativo, que interpreta directamente el archivo fuente .java
  3. El recolector de basura, que traduce el bytecode a código máquina
  4. La Máquina Virtual de Java (JVM), que ejecuta el bytecode generado

El código Java se compila a bytecode independiente de la plataforma, el cual es ejecutado por la JVM en cualquier sistema donde esta esté instalada, logrando 'write once, run anywhere'. (The Java Language Specification, cap. 4; The Java Virtual Machine Specification)

32. Cuando se compila un programa escrito en Java, ¿a qué se traduce el código fuente antes de poder ejecutarse?

  1. A código máquina nativo del procesador de destino
  2. A bytecode almacenado en archivos .class, ejecutado por la JVM
  3. A un script interpretado directamente por el sistema operativo
  4. A un archivo binario compatible únicamente con un solo fabricante

El compilador de Java genera bytecode en archivos .class, que la Máquina Virtual de Java (JVM) ejecuta, proporcionando portabilidad entre plataformas. (The Java Virtual Machine Specification (Oracle), 'The class File Format'; The Java Language Specification, cap. 4)

33. La implementación de referencia de Python, conocida como CPython, ¿qué realiza con el código fuente antes de que la Máquina Virtual de Python (PVM) lo ejecute?

  1. Lo interpreta carácter por carácter sin generar ningún archivo intermedio
  2. Lo traduce a bytecode de la JVM para mayor portabilidad
  3. Lo compila a bytecode (.pyc), que después interpreta la PVM
  4. Lo compila directamente a código máquina nativo del procesador

CPython compila el código fuente a bytecode almacenado en archivos .pyc, el cual es interpretado por la Máquina Virtual de Python (PVM). (The Python Language Reference, sección Execution model)

34. A diferencia de Java, cuyo compilador genera bytecode ejecutado por la JVM, el compilador de C traduce el código fuente directamente a:

  1. Bytecode intermedio ejecutado por una máquina virtual
  2. Instrucciones ensambladas dinámicamente durante la ejecución
  3. Un lenguaje intermedio interpretado por el sistema operativo
  4. Código máquina nativo del procesador de destino

Una implementación típica de C compila el código fuente a código máquina nativo, sin una máquina virtual intermedia como la JVM. (A. V. Aho et al., Compilers: Principles, Techniques and Tools, cap. 1)

35. ¿En qué momento se verifica la compatibilidad de tipos de variables y expresiones en un lenguaje de tipado estático como Java o C#?

  1. En tiempo de ejecución, mientras el programa corre
  2. Cuando el recolector de basura libera memoria
  3. En tiempo de compilación, antes de ejecutar el programa
  4. Únicamente si el programador ejecuta pruebas manuales

El tipado estático verifica la compatibilidad de tipos en tiempo de compilación, antes de ejecutar el programa. (R. W. Sebesta, Concepts of Programming Languages, cap. 6; B. C. Pierce, Types and Programming Languages, cap. 1)

Comienza gratis