Ejecución del programa |
---|
Conceptos generales |
Tipos de codigo |
Estrategias de compilación |
Tiempos de ejecución notables |
|
Compiladores y cadenas de herramientas notables |
En programación imperativa , un programa de computadora es una secuencia de instrucciones en un lenguaje de programación que una computadora puede ejecutar o interpretar. [1] En programación declarativa , un programa de computadora es un conjunto de instrucciones.
Un programa de computadora en su forma legible por humanos se llama código fuente . El código fuente necesita otro programa de computadora para ejecutarse porque las computadoras solo pueden ejecutar sus instrucciones nativas de la máquina . Por lo tanto, el código fuente se puede traducir a instrucciones de máquina utilizando el compilador del lenguaje . (Los programas en lenguaje de máquina se traducen mediante un ensamblador ). El archivo resultante se denomina ejecutable . Alternativamente, el código fuente puede ejecutarse dentro del intérprete del idioma . El lenguaje de programación Java se compila en una forma intermedia que luego es ejecutada por unIntérprete de Java . [2]
Si se solicita la ejecución del ejecutable, el sistema operativo lo carga en la memoria e inicia un proceso . [3] La unidad central de procesamiento pronto cambiará a este proceso para que pueda buscar, decodificar y luego ejecutar cada instrucción de la máquina. [4]
Si se solicita la ejecución del código fuente, el sistema operativo carga el intérprete correspondiente en la memoria e inicia un proceso. Luego, el intérprete carga el código fuente en la memoria para traducir y ejecutar cada declaración. [2] Ejecutar el código fuente es más lento que ejecutar un ejecutable. Además, el intérprete debe estar instalado en la computadora.
En 1837, Charles Babbage se inspiró en el telar de Jacquard para intentar construir el motor analítico . [5] Los nombres de los componentes del dispositivo de cálculo se tomaron prestados de la industria textil. En la industria textil, el hilo se traía del almacén para ser molido. El dispositivo tenía una "tienda" que era memoria para almacenar 1000 números de 40 dígitos decimales cada uno. Los números de la "tienda" se transfirieron al "molino" para su procesamiento. Se programó mediante dos juegos de tarjetas perforadas. Uno para dirigir la operación y el otro para las variables de entrada. [5] [6]Sin embargo, después de más de 17.000 libras esterlinas del dinero del gobierno británico, los miles de engranajes y ruedas dentadas nunca funcionaron completamente juntos. [7]
Durante un período de nueve meses entre 1842 y 1843, Ada Lovelace tradujo las memorias del matemático italiano Luigi Menabrea . Las memorias cubrieron el motor analítico. La traducción contenía la Nota G que detallaba completamente un método para calcular los números de Bernoulli usando el motor analítico. Algunos historiadores reconocen esta nota como el primer programa informático escrito del mundo. [8]
En 1936, Alan Turing introdujo la máquina de Turing universal, un dispositivo teórico que puede modelar cada cálculo que se puede realizar en una máquina de computación completa de Turing . [9] Es una máquina de estados finitos que tiene una cinta de lectura / escritura infinitamente larga. La máquina puede mover la cinta hacia adelante y hacia atrás, cambiando su contenido a medida que realiza un algoritmo . La máquina arranca en el estado inicial, pasa por una secuencia de pasos y se detiene cuando encuentra el estado de parada. [10]
La computadora Z3 , inventada por Konrad Zuse (1941), era una computadora digital y programable. [11] Zuse se dio cuenta del "motor Babbage" en 1939 mientras intentaba presentar una patente alemana . [11] El motor analítico era de base 10 , que era fácil de comprender. Zuse reconoció que una máquina binaria era fácil de construir. Los relés telefónicos son interruptores de dos posiciones: abierto o cerrado. El Z3 tenía aproximadamente 2600 relés: 1800 para la memoria, 600 para la aritmética y 200 para el lector de cinta perforada , el teclado y la pantalla. [11] Los circuitos proporcionaron unacomputadora de punto flotante con nueve instrucciones. La programación del Z3 se realizó mediante un teclado y una cinta perforada especialmente diseñados. La entrada manual se realizó a través de un teclado estilo calculadora que aceptaba números decimales. La máquina convirtió la entrada a binaria y la pasó a través de una serie de módulos de cálculo. [7] El resultado se volvió a convertir a decimal y se mostró en un panel de salida. [11]
Simultáneamente se desarrolló su sucesor: el ordenador Z4 . (Un ataque aéreo el 6 de abril de 1945 destruyó el Z3.) En 1950, el Z4 se puso en producción en el Instituto Técnico Federal de Zúrich . Fue pionera en la corta permanencia de las computadoras basadas en retransmisiones. [11]
El Integrador Numérico Electrónico y Computadora (ENIAC) se construyó entre julio de 1943 y otoño de 1945. Era una computadora Turing completa de uso general que usaba 17.468 tubos de vacío para crear los circuitos . En esencia, era una serie de Pascalines conectados entre sí. [12] Sus 40 unidades pesaban 30 toneladas, ocupaban 1.800 pies cuadrados (167 m 2 ) y consumían $ 650 por hora ( en moneda de la década de 1940 ) en electricidad cuando estaban inactivos. [12] Tenía 20 acumuladores de base 10 . La programación de ENIAC tomó hasta dos meses. [12]Tres mesas de funciones estaban sobre ruedas y debían enrollarse en paneles de funciones fijas. Las mesas de funciones se conectaron a los paneles de funciones mediante cables negros pesados. Cada mesa de funciones tenía 728 botones giratorios. La programación del ENIAC también implicó configurar algunos de los 3.000 interruptores. La depuración de un programa llevó una semana. [13] Funcionó desde 1947 hasta 1955 en Aberdeen Proving Ground , calculando parámetros de bombas de hidrógeno, prediciendo patrones climáticos y produciendo tablas de disparo para apuntar cañones de artillería. [14]
En lugar de enchufar cables y encender interruptores, una computadora con programa almacenado carga sus instrucciones en la memoria tal como carga sus datos en la memoria. [15] Como resultado, la computadora podría programarse rápidamente y realizar cálculos a velocidades muy rápidas. [16] Presper Eckert y John Mauchly construyeron el ENIAC. Los dos ingenieros introdujeron el concepto de programa almacenado en un memorando de tres páginas con fecha de febrero de 1944. [17] Más tarde, en septiembre de 1944, el Dr. John von Neumann comenzó a trabajar en el proyecto ENIAC. El 30 de junio de 1945, von Neumann publicó el Primer Borrador de un Informe sobre el EDVACque equiparó las estructuras de la computadora con las estructuras del cerebro humano. [16] El diseño se conoció como la arquitectura de von Neumann . La arquitectura se implementó simultáneamente en las construcciones de las computadoras EDVAC y EDSAC en 1949. [18]
En 1961, el Burroughs B5000 se construyó específicamente para ser programado en el lenguaje Algol 60 . El hardware presentaba circuitos para facilitar la fase de compilación . [19]
En 1964, IBM System / 360 era una línea de seis computadoras, cada una con la misma arquitectura de conjunto de instrucciones . El Model 30 era el más pequeño y el menos caro. Los clientes pueden actualizar y conservar el mismo software de aplicación . [20] El Modelo 75 fue el más premium. Cada modelo de System / 360 presentaba multiprogramación [20] , con múltiples procesos en la memoria a la vez. Cuando un proceso estaba esperando entrada / salida , otro podía calcular.
IBM planeó que cada modelo se programara usando PL / 1 . [21] Se formó un comité que incluía programadores de COBOL , Fortran y ALGOL . El propósito era desarrollar un lenguaje que fuera completo, fácil de usar, extensible y que reemplazara a Cobol y Fortran. [21] El resultado fue un lenguaje extenso y complejo que llevó mucho tiempo compilar . [22]
Las computadoras fabricadas hasta la década de 1970 tenían interruptores en el panel frontal para la programación. [23] El programa informático se escribió en papel como referencia. Una instrucción estaba representada por una configuración de ajustes de encendido / apagado. Después de establecer la configuración, se presionó un botón de ejecución. Luego se repitió este proceso. Los programas de computadora también se ingresaron manualmente mediante cinta de papel o tarjetas perforadas . Después de que se cargó el medio, la dirección de inicio se estableció mediante interruptores y se presionó el botón de ejecución. [23]
La programación de computadoras (también conocida como desarrollo de software e ingeniería de software ) es el proceso de escribir o editar el código fuente . En un entorno formal, un analista de sistemas recopilará información de los gerentes sobre todos los procesos comerciales para automatizar. Este profesional luego prepara un plan detallado para el sistema nuevo o modificado. [24] El plan es análogo al plano de un arquitecto. [24] Un programador de computadoras es un especialista responsable de escribir o modificar el código fuente para implementar el plan detallado. [24]
Un lenguaje de programación es un conjunto de palabras clave , símbolos , identificadores y reglas mediante los cuales los programadores pueden comunicar instrucciones a la computadora. [25] Siguen un conjunto de reglas llamadas sintaxis . [25]
Los lenguajes de programación obtienen su base de los lenguajes formales . [26] El propósito de definir una solución en términos de su lenguaje formal es generar un algoritmo para resolver el problema subyacente. [26] Un algoritmo es una secuencia de instrucciones simples que resuelven un problema. [27]
La evolución de los lenguajes de programación comenzó cuando el EDSAC (1949) utilizó el primer programa de computadora almacenado en su arquitectura von Neumann . [28] La programación del EDSAC estaba en la primera generación de lenguajes de programación .
Los lenguajes imperativos especifican un algoritmo secuencial mediante declaraciones, expresiones y enunciados: [37]
var x: integer;
2 + 2
produce 4x := 2 + 2; if x = 4 then do_something();
FORTRAN (1958) fue presentado como "El sistema IBM Mathematical FORmula TRANslates". Se compiló correctamente por primera vez en 1958. [39] Fue diseñado para cálculos científicos, sin instalaciones de manipulación de cuerdas . Junto con declaraciones , expresiones y declaraciones , admitió:
Tuvo éxito porque:
Sin embargo, los proveedores que no eran de IBM también escribieron compiladores de Fortran, pero con una sintaxis que probablemente fallaría al compilador de IBM. [39] El American National Standards Institute (ANSI) desarrolló el primer estándar Fortran en 1966. En 1978, Fortran 77 se convirtió en el estándar hasta 1991. Fortran 90 admite:
COBOL (1959) son las siglas de "Common Business Oriented Language". Fortran manipuló los símbolos. Pronto se dio cuenta de que los símbolos no necesitaban ser números, por lo que se introdujeron cadenas. [40] El Departamento de Defensa de EE. UU. Influyó en el desarrollo de COBOL, siendo Grace Hopper uno de los principales contribuyentes. Las declaraciones eran detalladas y parecidas al inglés. El objetivo era diseñar un lenguaje para que los gerentes pudieran leer los programas. Sin embargo, la falta de declaraciones estructuradas obstaculizó este objetivo. [41]
El desarrollo de COBOL fue estrictamente controlado, por lo que no surgieron dialectos que requirieran estándares ANSI. Como consecuencia, no se cambió durante 25 años hasta 1974. La versión de la década de 1990 hizo cambios importantes, como la programación orientada a objetos . [41]
ALGOL (1960) son las siglas de "ALGOrithmic Language". Tuvo una profunda influencia en el diseño de lenguajes de programación. [42] Surgió de un comité de expertos en lenguajes de programación europeos y estadounidenses, usó notación matemática estándar y tenía un diseño estructurado legible. Algol fue el primero en definir su sintaxis utilizando la forma Backus-Naur . [42] Esto llevó a compiladores dirigidos por sintaxis . Agregó características como:
Los descendientes directos de Algol incluyen Pascal , Modula-2 , Ada , Delphi y Oberon en una rama. En otra rama están C , C ++ y Java . [42]
BÁSICO (1964) son las siglas de "Código de instrucción simbólico de uso múltiple para principiantes". Fue desarrollado en Dartmouth College para que todos sus estudiantes lo aprendan. [43] Si un estudiante no pasaba a un lenguaje más poderoso, el estudiante aún recordaría Basic. [43] Se instaló un intérprete básico en las microcomputadoras fabricadas a fines de la década de 1970. A medida que crecía la industria de las microcomputadoras, también lo hacía el idioma. [43]
Basic fue pionero en la sesión interactiva . [43] Ofreció comandos del sistema operativo dentro de su entorno:
Sin embargo, la sintaxis básica era demasiado simple para programas grandes. [43] Los dialectos recientes han agregado estructuras y extensiones orientadas a objetos. Visual Basic de Microsoft todavía se usa ampliamente y produce una interfaz gráfica de usuario . [44]
El lenguaje de programación C (1973) obtuvo su nombre porque el lenguaje BCPL fue reemplazado por B , y AT&T Bell Labs llamó a la siguiente versión "C". Su propósito era escribir el sistema operativo UNIX . [34] C es un lenguaje relativamente pequeño, lo que facilita la escritura de compiladores. Su crecimiento reflejó el crecimiento del hardware en la década de 1980. [34] Su crecimiento también se debió a que tiene las facilidades del lenguaje ensamblador , pero usa una sintaxis de alto nivel . Agregó características avanzadas como:
C permite al programador controlar qué región de datos de la memoria se almacenará. Las variables globales y las variables estáticas requieren la menor cantidad de ciclos de reloj para almacenar. La pila se utiliza automáticamente para las declaraciones de variables estándar. La memoria de pila se devuelve a una variable de puntero desde la malloc()función.
main()
función. [46] Las variables globales son visibles main()
y todas las demás funciones del código fuente.main()
otras funciones o dentro de los {
}
delimitadores de bloque son variables locales . Las variables locales también incluyen variables de parámetros formales . Las variables de parámetro se incluyen entre paréntesis de las definiciones de funciones. [47] Proporcionan una interfaz para la función.static
prefijo también se almacenan en la región de datos globales y estáticos . [45] A diferencia de las variables globales, las variables estáticas solo son visibles dentro de la función o bloque. Las variables estáticas siempre conservan su valor. Un ejemplo de uso sería la funciónint increment_counter(){ static int counter = 0; counter++; return counter;}
static
prefijo, incluidas las variables de parámetros formales, [49] se denominan variables automáticas [46] y se almacenan en la pila. [45] Son visibles dentro de la función o bloque y pierden su alcance al salir de la función o bloque.En la década de 1970, los ingenieros de software necesitaban soporte lingüístico para dividir los grandes proyectos en módulos . [52] Una característica obvia era descomponer grandes proyectos físicamente en archivos separados . Una característica menos obvia fue descomponer los grandes proyectos de manera lógica en tipos de datos abstractos . [52] En ese momento, los lenguajes admitían tipos de datos concretos ( escalares ) como números enteros , números de punto flotante y cadenas de caracteres . Los tipos de datos concretos tienen su representación como parte de su nombre.[53] Los tipos de datos abstractos son estructuras de tipos de datos concretos, con un nuevo nombre asignado. Por ejemplo, sepodría llamar auna lista de números enterosinteger_list
.
En la jerga orientada a objetos, los tipos de datos abstractos se denominan clases . Sin embargo, una clase es solo una definición; no se asigna memoria. Cuando se asigna memoria a una clase, se denomina objeto . [54]
Lenguajes imperativos orientados a objetos desarrollados combinando la necesidad de clases y la necesidad de una programación funcional segura. [55] Una función, en un lenguaje orientado a objetos, se asigna a una clase. Una función asignada se denomina método , función miembro u operación . La programación orientada a objetos está ejecutando operaciones sobre objetos . [56]
Los lenguajes orientados a objetos admiten una sintaxis para modelar relaciones de subconjunto / superconjunto . En la teoría de conjuntos , un elemento de un subconjunto hereda todos los atributos contenidos en el superconjunto. Por ejemplo, un estudiante es una persona. Por tanto, el conjunto de estudiantes es un subconjunto del conjunto de personas. Como resultado, los estudiantes heredan todos los atributos comunes a todas las personas. Además, los estudiantes tienen atributos únicos que otras personas no tienen. Los lenguajes orientados a objetos modelan relaciones de subconjunto / superconjunto utilizando la herencia . [57] La programación orientada a objetos se convirtió en el paradigma del lenguaje dominante a finales de la década de 1990. [52]
C ++ (1985) se llamó originalmente "C con clases". [58] Fue diseñado para expandir las capacidades de C agregando las facilidades orientadas a objetos del lenguaje Simula . [59]
Un módulo orientado a objetos se compone de dos archivos. El archivo de definiciones se denomina archivo de encabezado . Aquí hay un archivo de encabezado de C ++ para la clase GRADE en una aplicación escolar simple:
// grade.h // -------// Se utiliza para permitir que varios archivos fuente incluyan // este archivo de encabezado sin errores de duplicación. // ---------------------------------------------- #ifndef GRADE_H #define GRADE_Hclass GRADE { publico : // Esta es la operación del constructor. // ---------------------------------- GRADE ( letra const char ); // Esta es una variable de clase. // ------------------------- letra char ; // Esta es una operación de miembro. // --------------------------- int grade_numeric ( const char letter ); // Esta es una variable de clase. // ------------------------- int numérico ; };#terminara si
Una operación de constructor es una función con el mismo nombre que el nombre de la clase. [60] Se ejecuta cuando la operación de llamada ejecuta la new
instrucción.
El otro archivo de un módulo es el archivo fuente . Aquí hay un archivo fuente de C ++ para la clase GRADE en una aplicación escolar simple:
// grade.cpp // --------- #include "grade.h" GRADE :: GRADE ( letra const char ) { // Haga referencia al objeto usando la palabra clave 'esto'. // ---------------------------------------------- esto - > letra = letra ; este -> numérico = grade_numeric ( carta ); }int GRADE :: grade_numeric ( letra de carácter constante ) { si ( ( letra == 'A' || letra == 'a' ) ) volver 4 ; demás si ( ( letra == 'B' || letra == 'b' ) ) volver 3 ; demás si ( ( letra == 'C' || letra == 'c' ) ) volver 2 ; demás si ( ( letra == 'D' || letra == 'd' ) ) return 1 ; demás si ( ( letra == 'F' || letra == 'f' ) ) return 0 ; demás return -1 ; }
Aquí hay un archivo de encabezado de C ++ para la clase PERSON en una aplicación escolar simple:
// person.h // -------- #ifndef PERSON_H #define PERSON_Hclase PERSONA { publico : PERSONA ( const char * nombre ); const char * nombre ; };#terminara si
Aquí hay un código fuente de C ++ para la clase PERSON en una aplicación escolar simple:
// person.cpp // ---------- #include "person.h" PERSON :: PERSON ( const char * name ) { esto -> nombre = nombre ; }
Aquí hay un archivo de encabezado de C ++ para la clase ESTUDIANTE en una aplicación escolar simple:
// estudiante.h // --------- #ifndef ESTUDIANTE_H #define ESTUDIANTE_H#include "person.h" #include "grade.h" // UN ESTUDIANTE es un subconjunto de PERSONA. // -------------------------------- clase ESTUDIANTE : PERSONA pública { publico : ESTUDIANTE ( const char * nombre ); GRADO * grado ; };#terminara si
Aquí hay un código fuente de C ++ para la clase ESTUDIANTE en una aplicación escolar simple:
// estudiante.cpp // ----------- #incluir "estudiante.h" #include "person.h" ESTUDIANTE :: ESTUDIANTE ( const char * nombre ) : // Ejecuta el constructor de la superclase PERSON. // ------------------------------------------------ - PERSONA ( nombre ) { // Nada más que hacer. // ------------------- }
Aquí hay un programa de controlador para demostración:
// student_dvr.cpp // --------------- #include <iostream> #include "estudiante.h" int main ( vacío ) { ESTUDIANTE * estudiante = nuevo ESTUDIANTE ( "El Estudiante" ); estudiante -> grado = nuevo GRADO ( 'a' ); std :: cout // Note que el estudiante hereda el nombre de la PERSONA << estudiante -> nombre << ": Grado numérico =" << estudiante -> grado -> numérico << " \ n " ; return 0 ; }
Aquí hay un archivo MAKE para compilar todo:
# makefile # -------- todos : student_dvrlimpiar : rm student_dvr * .oestudiante_dvr : estudiante_dvr . grado cpp . o estudiante . o persona . o c ++ student_dvr.cpp grade.o student.o person.o -o student_dvrgrade.o : grado . grado cpp . h c ++ -c grado.cppestudiante.o : estudiante . estudiante cpp . h c ++ -c estudiante.cppperson.o : persona . persona cpp . h c ++ -c person.cpp
Los lenguajes imperativos tienen una crítica importante: asignar una expresión a una variable no local puede producir un efecto secundario no deseado . [61] Los lenguajes declarativos generalmente omiten la declaración de asignación y el flujo de control. Describen qué cálculo se debe realizar y no cómo calcularlo. Dos amplias categorías de lenguajes declarativos son los lenguajes funcionales y los lenguajes lógicos .
El principio detrás de un lenguaje funcional es utilizar el cálculo lambda como guía para una semántica bien definida . [62] En matemáticas, una función es una regla que mapea elementos de una expresión a un rango de valores . Considere la función:
times_10(x) = 10 * x
La función asigna la expresión a un rango de valores . Un valor resulta ser 20. Esto ocurre cuando x es 2. Entonces, la aplicación de la función se escribe matemáticamente como:10 * x
times_10()
times_10(2) = 20
Un compilador de lenguaje funcional no almacenará este valor en una variable. En su lugar, empujará el valor a la pila de la computadora antes de volver a configurar el contador del programa en la función de llamada. La función que llama a continuación, hacer estallar el valor de la pila. [63]
Los lenguajes imperativos apoyan funciones. Por lo tanto, la programación funcional se puede lograr en un lenguaje imperativo, si el programador usa la disciplina. Sin embargo, los lenguajes funcionales imponen esta disciplina al programador a través de su sintaxis. Los lenguajes funcionales tienen una sintaxis adaptada para enfatizar el qué . [64]
Un programa funcional se desarrolla con un conjunto de funciones primitivas seguidas de una única función de controlador. [61] Considere el fragmento :
function max(a,b){ /* code omitted */}
function min(a,b){ /* code omitted */}
function difference_between_largest_and_smallest(a,b,c) {
return max(a,max(b,c)) - min(a, min(b,c));
}
Los primitivos son max()
y min()
. La función del controlador es difference_between_largest_and_smallest()
. Ejecutando:
put(difference_between_largest_and_smallest(10,4,7));
saldrá 6.
Los lenguajes funcionales se utilizan en la investigación de la informática para explorar nuevas características del lenguaje. [65] Además, su falta de efectos secundarios los ha hecho populares en la programación paralela y la programación concurrente . [66] Sin embargo, los desarrolladores de aplicaciones prefieren las características orientadas a objetos de los lenguajes imperativos . [66]
Lisp (1958) son las siglas de "LISt Processor". [67] Está diseñado para procesar listas . Se forma una estructura completa de los datos mediante la creación de listas de listas. En la memoria, se construye una estructura de datos de árbol . Internamente, la estructura de árbol se presta muy bien para funciones recursivas . [68] La sintaxis para construir un árbol es encerrar los elementos separados por espacios entre paréntesis. La siguiente es una lista de tres elementos. Los dos primeros elementos son en sí mismos listas de dos elementos:
((A B) (HELLO WORLD) 94)
Lisp tiene funciones para extraer y reconstruir elementos. [69] La función head()
devuelve una lista que contiene el primer elemento de la lista. La función tail()
devuelve una lista que contiene todo menos el primer elemento. La función cons()
devuelve una lista que es la concatenación de otras listas. Por tanto, la siguiente expresión devolverá la lista x
:
cons(head(x), tail(x))
Un inconveniente de Lisp es que cuando muchas funciones están anidadas, los paréntesis pueden parecer confusos. [64] Los entornos Lisp modernos ayudan a asegurar la coincidencia de paréntesis. Como acotación al margen, Lisp admite las operaciones de lenguaje imperativas de la instrucción de asignación y los bucles goto. [70] Además, Lisp no se preocupa por el tipo de datos de los elementos en tiempo de compilación. En cambio, asigna los tipos de datos en tiempo de ejecución. Esto puede provocar que los errores de programación no se detecten al principio del proceso de desarrollo.
Escribir programas Lisp grandes, fiables y legibles requiere previsión. Si se planifica adecuadamente, el programa puede ser mucho más corto que un programa equivalente de lenguaje imperativo . [64] Lisp se usa ampliamente en inteligencia artificial . Sin embargo, su uso ha sido aceptado solo porque tiene operaciones lingüísticas imperativas , lo que hace posibles efectos secundarios no deseados. [66]
ML (1973) [71] son las siglas de "Meta Language". ML comprueba para asegurarse de que solo se comparen datos del mismo tipo entre sí. [72] Por ejemplo, esta función tiene un parámetro de entrada (un número entero) y devuelve un número entero:
fun times_10(n : int) : int = 10 * n;
ML no es excéntrico entre paréntesis como Lisp . La siguiente es una aplicación de times_10()
:
times_10 2
Devuelve "20: int". (Se devuelven tanto los resultados como el tipo de datos).
Como Lisp , ML está diseñado para procesar listas. A diferencia de Lisp , cada elemento es del mismo tipo de datos. [73]
Prolog (1972) son las siglas de "PROGRAMACIÓN EN LÓGICO". Fue diseñado para procesar lenguajes naturales . [74] Los componentes básicos de un programa Prolog son los objetos y sus relaciones con otros objetos. Los objetos se construyen indicando hechos reales sobre ellos. [75]
Los hechos de la teoría de conjuntos se forman asignando objetos a conjuntos. La sintaxis essetName(object).
animal(cat).
animal(mouse).
cat(tom).
mouse(jerry).
Los hechos adjetivos se forman usandoadjective(object).
big(cat).
small(mouse).
Las relaciones se forman utilizando varios elementos entre paréntesis. En nuestro ejemplo tenemos verb(object,object).
yverb(adjective,adjective).
eat(mouse,cheese).
eat(big,small).
Después de ingresar todos los hechos y relaciones, se puede hacer una pregunta:
?- eat(tom,jerry).
El uso de Prolog se ha expandido para convertirse en un lenguaje orientado a objetivos. [76] En una aplicación orientada a objetivos, el objetivo se define proporcionando una lista de subobjetivos. Luego, cada subobjetivo se define proporcionando además una lista de sus subobjetivos, etc. Si un camino de subobjetivos no logra encontrar una solución, entonces ese subobjetivo se retrocede y se intenta sistemáticamente otro camino. [75] Las aplicaciones prácticas incluyen resolver el problema del camino más corto [74] y producir árboles genealógicos . [77]
La programación modular es una técnica para refinar programas de lenguaje imperativos . Un módulo de programa es una secuencia de declaraciones que están delimitadas dentro de un bloque y juntas identificadas por un nombre. [78] Los módulos tienen una función , contexto y lógica : [79]
El nombre del módulo debe derivarse primero por su función , luego por su contexto . Su lógica no debería formar parte del nombre. [79] Por ejemplo, function compute_square_root( x )
o function compute_square_root_integer( i : integer )
son nombres de módulo apropiados. Sin embargo, function compute_square_root_by_division( x )
no lo es.
El grado de interacción dentro de un módulo es su nivel de cohesión . [79] La cohesión es un juicio de la relación entre el nombre de un módulo y su función . El grado de interacción entre módulos es el nivel de acoplamiento . [80] El acoplamiento es un juicio de la relación entre el contexto de un módulo y los elementos sobre los que se realiza.
Los niveles de cohesión de peor a mejor son: [81]
function read_sales_record_print_next_line_convert_to_float()
. La cohesión coincidente ocurre en la práctica si la gerencia hace cumplir reglas tontas. Por ejemplo, "Cada módulo tendrá entre 35 y 50 sentencias ejecutables". [81]function perform_arithmetic( perform_addition )
.function initialize_variables_and_open_files()
. Otro ejemplo, stage_one()
, stage_two()
, ...function read_part_number_update_employee_record()
.function read_part_number_update_sales_record()
.Los niveles de acoplamiento de peor a mejor son: [80]
perform_arithmetic( perform_addition )
. En cambio, el control debe estar en la composición del objeto devuelto.El análisis de flujo de datos es un método de diseño utilizado para lograr módulos de cohesión funcional y acoplamiento de datos . [82] La entrada al método es un diagrama de flujo de datos . Un diagrama de flujo de datos es un conjunto de óvalos que representan módulos. El nombre de cada módulo se muestra dentro de su óvalo. Los módulos pueden estar en el nivel ejecutable o en el nivel de función.
El diagrama también tiene flechas que conectan módulos entre sí. Las flechas que apuntan a los módulos representan un conjunto de entradas. Cada módulo debe tener solo una flecha apuntando hacia afuera para representar su único objeto de salida. (Opcionalmente, señala una flecha de excepción adicional). Una cadena de óvalos transmitirá un algoritmo completo . Los módulos de entrada deben iniciar el diagrama. Los módulos de entrada deben conectarse a los módulos de transformación. Los módulos de transformación deben conectarse a los módulos de salida. [83]
La programación orientada a objetos no necesita limitarse a un lenguaje orientado a objetos . [84] La programación orientada a objetos está ejecutando operaciones sobre objetos . [56] En los lenguajes orientados a objetos, las clases son objetos. En los lenguajes no orientados a objetos, las estructuras de datos (que también se conocen como registros ) también pueden ser objetos. Para convertir una estructura de datos en un objeto, las operaciones deben escribirse específicamente para la estructura. La estructura resultante se denomina tipo de datos abstracto . [85] Sin embargo, faltará la herencia . No obstante, esta deficiencia puede superarse.
Aquí hay un archivo de encabezado del lenguaje de programación C para el tipo de datos abstracto GRADE en una aplicación escolar simple:
/ * grado.h * // * ------- * // * Se utiliza para permitir que varios archivos fuente incluyan * // * este archivo de encabezado sin errores de duplicación. * // * ---------------------------------------------- * /#ifndef GRADE_H #define GRADE_Htypedef struct { letra char ; } GRADE ; / * Constructor * // * ----------- * /GRADO * grade_new ( letra de carácter ); int grade_numeric ( letra de carácter ); #terminara si
La grade_new()
función realiza el mismo algoritmo que la operación del constructor de C ++ .
Aquí hay un archivo fuente del lenguaje de programación C para el tipo de datos abstracto GRADE en una aplicación escolar simple:
/ * grado.c * // * ------- * /#include "grade.h" GRADE * grade_new ( letra de carácter ) { GRADO * grado ; / * Asignar memoria dinámica * / / * -------------------- * / if ( ! ( grado = calloc ( 1 , tamaño de ( GRADO ) ) ) ) { fprintf ( stderr , "ERROR en% s /% s /% d: calloc () devuelto vacío. \ N " , __FILE__ , __FUNCIÓN__ , __LINE__ ); salida ( 1 ); } grado -> letra = letra ; grado de retorno ; }int grade_numeric ( letra de carácter ) { si ( ( letra == 'A' || letra == 'a' ) ) volver 4 ; demás si ( ( letra == 'B' || letra == 'b' ) ) volver 3 ; demás si ( ( letra == 'C' || letra == 'c' ) ) volver 2 ; demás si ( ( letra == 'D' || letra == 'd' ) ) return 1 ; demás si ( ( letra == 'F' || letra == 'f' ) ) return 0 ; demás return -1 ; }
En el constructor, la función calloc()
se usa en lugar de malloc()
porque cada celda de memoria se establecerá en cero.
Aquí hay un archivo de encabezado del lenguaje de programación C para el tipo de datos abstracto PERSON en una aplicación escolar simple:
/ * persona.h * // * -------- * /#ifndef PERSON_H #define PERSON_Htypedef struct { char * nombre ; } PERSONA ; / * Constructor * // * ----------- * /PERSON * person_new ( char * nombre ); #terminara si
Aquí hay un código fuente del lenguaje de programación C para el tipo de datos abstracto PERSON en una aplicación escolar simple:
/ * persona.c * // * -------- * /#include "person.h" PERSON * person_new ( char * nombre ) { PERSONA * persona ; / * Asignar memoria dinámica * / / * -------------------- * / si ( ! ( persona = calloc ( 1 , tamaño de ( PERSONA ) ) ) ) { fprintf ( stderr , "ERROR en% s /% s /% d: calloc () devuelto vacío. \ N " , __FILE__ , __FUNCIÓN__ , __LINE__ ); salida ( 1 ); } persona -> nombre = nombre ; persona de regreso ; }
Aquí hay un archivo de encabezado del lenguaje de programación C para el tipo de datos abstracto ESTUDIANTE en una aplicación escolar simple:
/ * estudiante.h * // * --------- * /#ifndef STUDENT_H #define STUDENT_H#include "person.h" #include "grade.h" typedef struct { / * UN ESTUDIANTE es un subconjunto de PERSONA. * / / * -------------------------------- * / PERSONA * persona ; GRADO * grado ; } ESTUDIANTE ; / * Constructor * // * ----------- * /ESTUDIANTE * estudiante_nuevo ( carácter * nombre ); #terminara si
Aquí hay un código fuente del lenguaje de programación C para el tipo de datos abstracto ESTUDIANTE en una aplicación escolar simple:
/ * estudiante.c * // * --------- * /#include "estudiante.h" #include "person.h" ESTUDIANTE * estudiante_nuevo ( carácter * nombre ) { ESTUDIANTE * estudiante ; / * Asignar memoria dinámica * / / * -------------------- * / if ( ! ( estudiante = calloc ( 1 , tamaño de ( ESTUDIANTE ) ) ) ) { fprintf ( stderr , "ERROR en% s /% s /% d: calloc () devuelto vacío. \ N " , __FILE__ , __FUNCIÓN__ , __LINE__ ); salida ( 1 ); } / * Ejecuta el constructor de la superclase PERSON. * / / * ------------------------------------------------ - * / estudiante -> persona = person_new ( nombre ); estudiante de regreso ; }
Aquí hay un programa de controlador para demostración:
/ * student_dvr.c * // * ------------- * /#include <stdio.h> #include "estudiante.h" int main ( vacío ) { ESTUDIANTE * estudiante = student_new ( "El estudiante" ); estudiante -> grado = grado_nuevo ( 'a' ); printf ( "% s: Calificación numérica =% d \ n " , / * Mientras que existe un subconjunto, la herencia no. * / estudiante -> persona -> nombre , / * La programación funcional está ejecutando funciones justo a tiempo (JIT) * / grade_numeric ( estudiante -> grado -> letra ) ); return 0 ; }
Aquí hay un archivo MAKE para compilar todo:
# makefile # -------- todos : student_dvrlimpiar : rm student_dvr * .oestudiante_dvr : estudiante_dvr . grado c . o estudiante . o persona . o gcc student_dvr.c grade.o student.o person.o -o student_dvrgrade.o : grado . grado c . h gcc -c grado.cestudiante.o : estudiante . c estudiante . h gcc -c estudiante.cperson.o : persona . c persona . h gcc -c persona.c
La estrategia formal para construir objetos orientados a objetos es: [86]
Por ejemplo:
Los programas de computadora pueden clasificarse según líneas funcionales. Las principales categorías funcionales son el software de aplicación y el software del sistema . El software del sistema incluye el sistema operativo que combina el hardware de la computadora con el software de la aplicación. [87] El propósito del sistema operativo es proporcionar un entorno en el que el software de aplicación se ejecute de manera conveniente y eficiente. [87] Además del sistema operativo, el software del sistema incluye programas integrados , programas de arranque y microprogramas . El software de aplicación diseñado para usuarios finales tiene una interfaz de usuario. El software de aplicación no diseñado para usuarios finales incluye middleware , que combina una aplicación con otra. Tanto el software del sistema como el software de la aplicación ejecutan programas de utilidad .
El software de aplicación es la clave para desbloquear el potencial del sistema informático. [88] El software de aplicación empresarial agrupa aplicaciones de contabilidad, personal, clientes y proveedores. Los ejemplos incluyen la planificación de recursos empresariales , la gestión de relaciones con los clientes y el software de gestión de la cadena de suministro .
Las aplicaciones empresariales pueden desarrollarse internamente como un software propietario único en su tipo . [88] Alternativamente, pueden adquirirse como software estándar . El software comprado puede modificarse para proporcionar software personalizado . Si la aplicación está personalizada, entonces se utilizan los recursos de la empresa o se subcontratan los recursos. El desarrollo de software subcontratado puede provenir del proveedor de software original o de un desarrollador externo. [88]
Las ventajas del software propietario son las características y los informes pueden ser exactos según las especificaciones. [89] La dirección también puede participar en el proceso de desarrollo y ofrecer un nivel de control. La gerencia puede decidir contrarrestar la nueva iniciativa de un competidor o implementar un requisito de un cliente o proveedor. Una fusión o adquisición requerirá cambios en el software empresarial. [89] Las desventajas del software propietario son que los costos de tiempo y recursos pueden ser elevados. [89] Además, pueden surgir riesgos relacionados con las características y el rendimiento.
Las ventajas del software estándar son sus costos iniciales identificables, las necesidades básicas deben satisfacerse y su rendimiento y confiabilidad tienen un historial. [89] Las desventajas del software estándar son que puede tener características innecesarias que confunden a los usuarios finales, puede carecer de características que la empresa necesita y el flujo de datos puede no coincidir con los procesos de trabajo de la empresa. [89]
Un enfoque para obtener económicamente una aplicación empresarial personalizada es a través de un proveedor de servicios de aplicaciones . [90] Las empresas especializadas proporcionan el hardware, el software personalizado y la asistencia al usuario final. Pueden acelerar el desarrollo de nuevas aplicaciones porque poseen personal capacitado en sistemas de información. La mayor ventaja es que libera los recursos internos de la dotación de personal y la gestión de proyectos informáticos complejos. [90] Muchos proveedores de servicios de aplicaciones se dirigen a empresas pequeñas de rápido crecimiento con recursos limitados de sistemas de información. [90]Por otro lado, es probable que las empresas más grandes con sistemas importantes cuenten con su infraestructura técnica. Un riesgo es tener que confiar en una organización externa con información sensible. Otro riesgo es tener que confiar en la confiabilidad de la infraestructura del proveedor. [90]
Un sistema operativo es el software de bajo nivel que admite las funciones básicas de una computadora, como programar tareas y controlar periféricos . [87]
En la década de 1950, el programador, que también era el operador, escribía un programa y lo ejecutaba. Una vez que el programa terminó de ejecutarse, es posible que la salida se haya impreso o que se haya perforado en cinta de papel o tarjetas para su posterior procesamiento. [23] La mayoría de las veces, el programa no funcionó. El programador luego miró las luces de la consola y jugueteó con los interruptores de la consola. Si era menos afortunado, se hizo una copia impresa de la memoria para su posterior estudio. En la década de 1960, los programadores redujeron la cantidad de tiempo perdido al automatizar el trabajo del operador. Un programa llamado sistema operativo se mantuvo en la computadora en todo momento. [91]
El término sistema operativo puede referirse a dos niveles de software. [92] El sistema operativo puede referirse al programa del núcleo que administra los procesos , la memoria y los dispositivos . De manera más amplia, el sistema operativo puede referirse al paquete completo del software central. El paquete incluye un programa de kernel, un intérprete de línea de comandos , una interfaz gráfica de usuario , programas de utilidad y un editor . [92]
Originalmente, los sistemas operativos se programaban en ensamblador ; sin embargo, los sistemas operativos modernos suelen estar escritos en lenguajes de nivel superior como C , C ++ , Objective-C y Swift .
Un programa de utilidad está diseñado para ayudar a la administración del sistema y la ejecución del software. Los sistemas operativos ejecutan programas de utilidad de hardware para comprobar el estado de las unidades de disco, la memoria, los altavoces y las impresoras. [102] Un programa de utilidad puede optimizar la ubicación de un archivo en un disco lleno. Los programas de utilidades del sistema monitorean el desempeño del hardware y la red. Cuando una métrica está fuera de un rango aceptable, se genera una alerta de activación. [103]
Los programas de utilidad incluyen programas de compresión para que los archivos de datos se almacenen en menos espacio en disco. [102] Los programas comprimidos también ahorran tiempo cuando los archivos de datos se transmiten a través de la red. [102] Los programas de utilidad pueden clasificar y combinar conjuntos de datos. [103] Los programas de utilidad detectan virus informáticos .
Esta sección necesita expansión . Puedes ayudar añadiéndole . ( Octubre de 2021 ) |
Una computadora con programa almacenado requiere un programa de arranque inicial almacenado en su memoria de solo lectura para arrancar . Es para identificar e inicializar todos los aspectos del sistema, desde los registros del procesador hasta los controladores de dispositivos y el contenido de la memoria . [104] Después del proceso de inicialización, el programa de arranque carga el sistema operativo y configura el contador del programa para comenzar las operaciones normales.
Esta sección necesita expansión . Puedes ayudar añadiéndole . ( Octubre de 2021 ) |
Independientemente de la computadora host, un dispositivo de hardware puede tener un firmware integrado para controlar su funcionamiento. El firmware se utiliza cuando el programa de computadora rara vez o nunca se espera que cambie, o cuando no debe perderse cuando la energía está apagada. [91]
A mayor escala, se utiliza un microcontrolador integrado para controlar parte de un sistema más grande. [55] Los ejemplos incluyen componentes de aeronaves y sistemas de soporte vital. Las aplicaciones que se ejecutan en estos sistemas son grandes y complejas. Además, se ejecutan en tiempo real y deben ser robustos . [55] El Departamento de Defensa de los Estados Unidos contrató a CII Honeywell Bull para desarrollar Ada (1983) como un lenguaje de programación en tiempo real. [105]
Un elemento central de los sistemas en tiempo real es una función de tareas que permite el procesamiento en paralelo . También son importantes los controles de interrupción . [105]
Un programa de microcódigo es el intérprete de nivel inferior que controla la ruta de datos de las computadoras controladas por software. [106] (Los avances en hardware han migrado estas operaciones a circuitos de ejecución de hardware). [106] Las instrucciones de microcódigo permiten al programador implementar más fácilmente el nivel lógico digital [107]: el hardware real de la computadora. El nivel de lógica digital es el límite entre la informática y la ingeniería informática . [108]
Una puerta es un pequeño transistor que puede devolver una de dos señales: encendido o apagado. [109]
Estas cinco puertas forman los componentes básicos del álgebra binaria , las funciones lógicas digitales de la computadora.
Las instrucciones de microcódigo son mnemotécnicos que los programadores pueden usar para ejecutar funciones lógicas digitales en lugar de formarlas en álgebra binaria. Se almacenan en el almacén de control de una unidad central de procesamiento (CPU) . [110] Estas instrucciones a nivel de hardware mueven datos a lo largo de la ruta de datos .
Las instrucciones de microcódigo mueven datos entre los registros de una CPU y por toda la placa base . El ciclo de microinstrucciones comienza cuando el microsecuenciador usa su contador de microprogramas para buscar la siguiente instrucción de la máquina de la memoria de acceso aleatorio . [111] El siguiente paso es decodificar la instrucción de la máquina seleccionando la línea de salida adecuada al módulo de hardware. [112] El paso final es ejecutar la instrucción usando el conjunto de puertas del módulo de hardware.
Las instrucciones para realizar operaciones aritméticas se pasan a través de una unidad lógica aritmética (ALU). [113] La ALU tiene circuitos para realizar operaciones elementales para sumar, desplazar y comparar enteros. Al combinar y hacer un bucle de las operaciones elementales a través de la ALU, la CPU realiza su aritmética compleja.
Las instrucciones de microcódigo mueven datos entre la CPU y el controlador de memoria . Las instrucciones de microcódigo del controlador de memoria manipulan dos registros . El registro de dirección de memoria se utiliza para acceder a la dirección de cada celda de memoria. El registro de datos de la memoria se utiliza para configurar y leer el contenido de cada celda. [114]
Las instrucciones de microcódigo mueven datos entre la CPU y muchos buses de computadora . El bus del controlador de disco escribe y lee en unidades de disco duro . Los datos también se mueven entre la CPU y otras unidades funcionales a través del bus expreso de interconexión de componentes periféricos. [115]