C (lenguaje de programación) - C (programming language)

C
Texto en mayúsculas serif azul claro sobre fondo blanco y letra sans serif celeste muy grande C.
El lenguaje de programación C (a menudo denominado K&R ), el libro fundamental sobre C
Paradigma Multi-paradigma : imperativo ( procedimental ), estructurado
Diseñada por Dennis Ritchie
Desarrollador Dennis Ritchie & Bell Labs (creadores); ANSI X3J11 ( ANSI C ); ISO / IEC JTC1 / SC22 / WG14 (ISO C)
Apareció por primera vez 1972 ; Hace 49 años ( 1972 )
Lanzamiento estable
C17 / junio de 2018 ; hace 3 años ( 2018-06 )
Versión de vista previa
C2x ( N2596 ) / 11 de diciembre de 2020 ; Hace 10 meses ( 2020-12-11 )
Disciplina de mecanografía Estático , débil , manifiesto , nominal
SO Multiplataforma
Extensiones de nombre de archivo .c, .h
Sitio web www .iso .org / standard / 74528 .html
www .open-std .org / jtc1 / sc22 / wg14 /
Implementaciones importantes
K&R C , GCC , Clang , Intel C , C ++ Builder , Microsoft Visual C ++ , Watcom C
Dialectos
Ciclón , C paralelo unificado , Split-C , Cilk , C *
Influenciado por
B ( BCPL , CPL ), ALGOL 68 , Montaje , PL / I , FORTRAN
Influenciado
Numerosos : AMPL , AWK , csh , C ++ , C-- , C # , Objective-C , D , Go , Java , JavaScript , Julia , Limbo , LPC , Perl , PHP , Pike , Processing , Python , Rust , Seed7 , Vala , Verilog (HDL), Nim , Zig

C ( / s i / , como en la letra c ) es una de propósito general , de procedimiento ordenador lenguaje de programación de soporte de programación estructurado , alcance variable de léxico , y la recursión , con un sistema de tipo estático . Por diseño, C proporciona construcciones que se asignan de manera eficiente a las instrucciones típicas de la máquina . Ha encontrado un uso duradero en aplicaciones previamente codificadas en lenguaje ensamblador . Dichas aplicaciones incluyen sistemas operativos y varios programas de aplicación para arquitecturas de computadoras que van desde supercomputadoras hasta PLC y sistemas integrados .

Un sucesor del lenguaje de programación B , C fue desarrollado originalmente en Bell Labs por Dennis Ritchie entre 1972 y 1973 para construir utilidades que se ejecutan en Unix . Se aplicó para volver a implementar el kernel del sistema operativo Unix. Durante la década de 1980, C ganó popularidad gradualmente. Se ha convertido en uno de los lenguajes de programación más utilizados , con compiladores de C de varios proveedores disponibles para la mayoría de las arquitecturas y sistemas operativos de computadoras existentes . C ha sido estandarizado por ANSI desde 1989 ( ANSI C ) y por la Organización Internacional de Normalización (ISO).

C es un lenguaje procedimental imperativo . Fue diseñado para ser compilado para proporcionar acceso de bajo nivel a la memoria y las construcciones de lenguaje que se asignan de manera eficiente a las instrucciones de la máquina , todo con un soporte mínimo de tiempo de ejecución . A pesar de sus capacidades de bajo nivel, el lenguaje fue diseñado para fomentar la programación multiplataforma. Un programa C compatible con los estándares escrito teniendo en cuenta la portabilidad se puede compilar para una amplia variedad de plataformas informáticas y sistemas operativos con pocos cambios en su código fuente.

Desde 2000, C se ha clasificado constantemente entre los dos principales lenguajes en el índice TIOBE , una medida de la popularidad de los lenguajes de programación.

Visión general

Dennis Ritchie (derecha), el inventor del lenguaje de programación C, con Ken Thompson

Como la mayoría de los lenguajes de procedimiento en la tradición ALGOL , C tiene facilidades para la programación estructurada y permite el alcance y la recursividad de variables léxicas . Su sistema de tipo estático evita operaciones no deseadas. En C, todo el código ejecutable está contenido en subrutinas (también llamadas "funciones", aunque no estrictamente en el sentido de programación funcional ). Los parámetros de función siempre se pasan por valor (excepto matrices ). El paso por referencia se simula en C pasando explícitamente valores de puntero . El texto fuente del programa C tiene formato libre , y utiliza el punto y coma como terminador de declaraciones y llaves para agrupar bloques de declaraciones .

El lenguaje C también presenta las siguientes características:

  • El lenguaje tiene un número pequeño y fijo de palabras clave, que incluye un conjunto completo de control de flujo primitivas: if/else, for, do/while, while, y switch. Los nombres definidos por el usuario no se distinguen de las palabras clave por ningún tipo de sigilo .
  • Tiene un gran número de aritmética, bit a bit, y operadores lógicos: +, +=, ++, &, ||, etc.
  • Se puede realizar más de una asignación en una sola declaración.
  • Funciones:
    • Los valores de retorno de la función se pueden ignorar cuando no se necesitan.
    • Los indicadores de función y datos permiten un polimorfismo en tiempo de ejecución ad hoc .
    • Las funciones pueden no estar definidas dentro del alcance léxico de otras funciones.
  • La tipificación de datos es estática , pero se aplica débilmente ; todos los datos tienen un tipo, pero las conversiones implícitas son posibles.
  • La sintaxis de la declaración imita el contexto de uso. C no tiene una palabra clave "definir"; en cambio, una declaración que comienza con el nombre de un tipo se toma como declaración. No hay una palabra clave "función"; en cambio, una función se indica mediante la presencia de una lista de argumentos entre paréntesis.
  • Son posibles los tipos definidos por el usuario ( typedef ) y compuestos.
    • Los tipos de datos agregados heterogéneos ( struct) permiten acceder a los elementos de datos relacionados y asignarlos como una unidad.
    • Union es una estructura con miembros superpuestos; solo el último miembro almacenado es válido.
    • La indexación de matrices es una notación secundaria, definida en términos de aritmética de punteros. A diferencia de las estructuras, las matrices no son objetos de primera clase: no se pueden asignar ni comparar con operadores integrados únicos. No hay ninguna palabra clave "matriz" en uso o definición; en cambio, los corchetes indican matrices sintácticamente, por ejemplo month[11].
    • Los tipos enumerados son posibles con la enumpalabra clave. Son libremente interconvertibles con números enteros.
    • Las cadenas no son un tipo de datos distinto, pero se implementan convencionalmente como matrices de caracteres terminadas en nulo .
  • El acceso de bajo nivel a la memoria de la computadora es posible convirtiendo las direcciones de las máquinas en punteros escritos .
  • Los procedimientos (subrutinas que no devuelven valores) son un caso especial de función, con un tipo de retorno sin tipo void.
  • Un preprocesador realiza la definición de macros , la inclusión de archivos de código fuente y la compilación condicional .
  • Existe una forma básica de modularidad : los archivos se pueden compilar por separado y enlazar entre sí, con control sobre qué funciones y objetos de datos son visibles para otros archivos a través de staticy externatributos.
  • Las funciones complejas como la E / S , la manipulación de cadenas y las funciones matemáticas se delegan constantemente a las rutinas de la biblioteca .

Si bien C no incluye ciertas características que se encuentran en otros lenguajes (como la orientación a objetos y la recolección de basura ), estas se pueden implementar o emular, a menudo mediante el uso de bibliotecas externas (por ejemplo, GLib Object System o el recolector de basura Boehm ).

Relaciones con otros idiomas

Muchos lenguajes posteriores han tomado prestado directa o indirectamente de C, incluidos C ++ , C # , shell C de Unix , D , Go , Java , JavaScript (incluidos transpilers ), Julia , Limbo , LPC , Objective-C , Perl , PHP , Python , Ruby , Rust , Swift , Verilog y SystemVerilog (lenguajes de descripción de hardware). Estos lenguajes han extraído muchas de sus estructuras de control y otras características básicas de C. La mayoría de ellos (Python es una excepción dramática) también expresan una sintaxis muy similar a C, y tienden a combinar la sintaxis de expresiones y declaraciones reconocibles de C con el tipo subyacente. sistemas, modelos de datos y semántica que pueden ser radicalmente diferentes.

Historia

Desarrollos tempranos

Cronología del desarrollo del lenguaje
Año C estándar
1972 Nacimiento
1978 K&R C
1989/1990 ANSI C e ISO C
1999 C99
2011 C11
2017 C17
TBD C2x

El origen de C está estrechamente ligado al desarrollo del sistema operativo Unix , originalmente implementado en lenguaje ensamblador en un PDP-7 por Dennis Ritchie y Ken Thompson, incorporando varias ideas de colegas. Finalmente, decidieron portar el sistema operativo a un PDP-11 . La versión PDP-11 original de Unix también se desarrolló en lenguaje ensamblador.

Thompson deseaba un lenguaje de programación para hacer utilidades para la nueva plataforma. Al principio, intentó hacer un compilador de Fortran , pero pronto abandonó la idea. En cambio, creó una versión reducida del lenguaje de programación de sistemas BCPL desarrollado recientemente . La descripción oficial de BCPL no estaba disponible en ese momento, y Thompson modificó la sintaxis para que fuera menos prolija, produciendo una B similar pero algo más simple . Sin embargo, en última instancia, se escribieron pocas utilidades en B porque era demasiado lento y B no podía aprovechar las funciones de PDP-11, como la direccionabilidad de bytes .

En 1972, Ritchie comenzó a mejorar B, más notablemente agregando tipificación de datos para variables, lo que resultó en la creación de un nuevo lenguaje C. El compilador de C y algunas utilidades creadas con él se incluyeron en la Versión 2 de Unix .

En la versión 4 de Unix , lanzada en noviembre de 1973, el kernel de Unix se volvió a implementar ampliamente en C. Para entonces, el lenguaje C había adquirido algunas características poderosas, como los tipos. struct

El preprocesador se introdujo alrededor de 1973 a instancias de Alan Snyder y también en reconocimiento de la utilidad de los mecanismos de inclusión de archivos disponibles en BCPL y PL / I. Su versión original solo proporcionaba archivos incluidos y reemplazos simples de cadenas: #includey #definemacros sin parámetros. Poco después, fue ampliado, principalmente por Mike Lesk y luego por John Reiser, para incorporar macros con argumentos y compilación condicional.

Unix fue uno de los primeros núcleos de sistema operativo implementados en un lenguaje distinto al ensamblador . Ejemplos anteriores incluyen el sistema Multics (que fue escrito en PL / I ) y Master Control Program (MCP) para Burroughs B5000 (que fue escrito en ALGOL ) en 1961. Alrededor de 1977, Ritchie y Stephen C. Johnson hicieron cambios adicionales a el lenguaje para facilitar la portabilidad del sistema operativo Unix. El compilador de C portátil de Johnson sirvió como base para varias implementaciones de C en nuevas plataformas.

K&R C

La portada del libro The C Programming Language , primera edición, de Brian Kernighan y Dennis Ritchie

En 1978, Brian Kernighan y Dennis Ritchie publicaron la primera edición de The C Programming Language . Este libro, conocido por los programadores de C como K&R , sirvió durante muchos años como una especificación informal del lenguaje. La versión de C que describe se conoce comúnmente como " K&R C ". Como se lanzó en 1978, también se conoce como C78 . La segunda edición del libro cubre el estándar ANSI C posterior , que se describe a continuación.

K&R introdujo varias características de idioma:

  • Biblioteca de E / S estándar
  • long int tipo de datos
  • unsigned int tipo de datos
  • Los operadores de asignación compuesta de la forma (como ) se cambiaron a la forma (es decir, ) para eliminar la ambigüedad semántica creada por construcciones como , que se había interpretado como (disminuir en 10) en lugar de la posible intención ( sea ​​- 10).=op=-op=-=i=-10i =- 10ii = -10i

Incluso después de la publicación del estándar ANSI de 1989, durante muchos años K&R C todavía se consideró el " mínimo común denominador " al que los programadores de C se restringían cuando se deseaba la máxima portabilidad, ya que muchos compiladores más antiguos todavía estaban en uso, y porque K&R cuidadosamente escrito El código C también puede ser estándar C legal.

En las primeras versiones de C, solo las funciones que devuelven tipos distintos de intdeben declararse si se usan antes de la definición de la función; se suponía que las funciones utilizadas sin declaración previa devolvían el tipo int.

Por ejemplo:

long some_function();
/* int */ other_function();

/* int */ calling_function()
{
    long test1;
    register /* int */ test2;

    test1 = some_function();
    if (test1 > 0)
          test2 = 0;
    else
          test2 = other_function();
    return test2;
}

Los intespecificadores de tipo que se comentan se pueden omitir en K&R C, pero se requieren en estándares posteriores.

Dado que las declaraciones de funciones de K&R no incluían información sobre los argumentos de la función, no se realizaron comprobaciones del tipo de parámetro de la función , aunque algunos compiladores emitían un mensaje de advertencia si se llamaba a una función local con el número incorrecto de argumentos o si se realizaban varias llamadas a una función externa. utilizó diferentes números o tipos de argumentos. Se desarrollaron herramientas independientes, como la utilidad lint de Unix, que (entre otras cosas) podían comprobar la coherencia del uso de funciones en varios archivos de origen.

En los años posteriores a la publicación de K&R C, se agregaron varias características al lenguaje, respaldadas por compiladores de AT&T (en particular PCC ) y algunos otros proveedores. Estos incluyeron:

La gran cantidad de extensiones y la falta de acuerdo sobre una biblioteca estándar , junto con la popularidad del lenguaje y el hecho de que ni siquiera los compiladores de Unix implementaron con precisión la especificación K&R, llevaron a la necesidad de estandarización.

ANSI C e ISO C

A finales de los años setenta y ochenta, se implementaron versiones de C para una amplia variedad de computadoras centrales , miniordenadores y microcomputadoras , incluida la IBM PC , ya que su popularidad comenzó a aumentar significativamente.

En 1983, el American National Standards Institute (ANSI) formó un comité, X3J11, para establecer una especificación estándar de C. X3J11 basó el estándar C en la implementación de Unix; sin embargo, la parte no portátil de la biblioteca Unix C se entregó al grupo de trabajo IEEE 1003 para convertirse en la base del estándar POSIX de 1988 . En 1989, el estándar C fue ratificado como ANSI X3.159-1989 "Lenguaje de programación C". Esta versión del lenguaje a menudo se conoce como ANSI C , Standard C o, a veces, C89.

En 1990, la Organización Internacional de Normalización (ISO) adoptó el estándar ANSI C (con cambios de formato ) como ISO / IEC 9899: 1990, que a veces se denomina C90. Por lo tanto, los términos "C89" y "C90" se refieren al mismo lenguaje de programación.

ANSI, al igual que otros organismos nacionales de normalización, ya no desarrolla la norma C de forma independiente, sino que se somete a la norma C internacional, mantenida por el grupo de trabajo ISO / IEC JTC1 / SC22 / WG14. La adopción nacional de una actualización del estándar internacional ocurre típicamente dentro de un año de la publicación de ISO.

Uno de los objetivos del proceso de estandarización de C era producir un superconjunto de K&R C, incorporando muchas de las características no oficiales introducidas posteriormente. El comité de estándares también incluyó varias características adicionales, como prototipos de funciones (tomados de C ++), voidpunteros, soporte para conjuntos de caracteres internacionales y configuraciones regionales , y mejoras en el preprocesador. Aunque la sintaxis para las declaraciones de parámetros se aumentó para incluir el estilo utilizado en C ++, la interfaz K&R siguió estando permitida, por compatibilidad con el código fuente existente.

C89 es compatible con los compiladores de C actuales y la mayoría del código C moderno se basa en él. Cualquier programa escrito solo en Estándar C y sin suposiciones dependientes del hardware se ejecutará correctamente en cualquier plataforma con una implementación C conforme, dentro de sus límites de recursos. Sin tales precauciones, los programas pueden compilarse solo en una plataforma determinada o con un compilador en particular, debido, por ejemplo, al uso de bibliotecas no estándar, como las bibliotecas GUI , oa la dependencia de atributos específicos de la plataforma o del compilador, como como el tamaño exacto de los tipos de datos y el byte endianness .

En los casos en los que el código debe ser compilable por compiladores que cumplen con los estándares o basados ​​en K&R C, la __STDC__macro se puede usar para dividir el código en las secciones Estándar y K&R para evitar el uso en un compilador basado en C de K&R de características disponibles solo en Estándar. C.

Después del proceso de estandarización ANSI / ISO, la especificación del lenguaje C permaneció relativamente estática durante varios años. En 1995, se publicó la Enmienda Normativa 1 a la norma C de 1990 (ISO / IEC 9899 / AMD1: 1995, conocida informalmente como C95), para corregir algunos detalles y agregar un soporte más extenso para conjuntos de caracteres internacionales.

C99

1999 ISO C.pdf

La norma C fue revisada nuevamente a fines de la década de 1990, lo que llevó a la publicación de ISO / IEC 9899: 1999 en 1999, que se conoce comúnmente como " C99 ". Desde entonces, ha sido enmendado tres veces por corrección técnica.

C99 introdujo varias características nuevas, incluidas funciones en línea , varios tipos de datos nuevos (incluido long long intun complextipo para representar números complejos ), matrices de longitud variable y miembros de matriz flexibles , soporte mejorado para IEEE 754 de punto flotante, soporte para macros variadic (macros de variable arity ) y soporte para comentarios de una línea que comiencen con //, como en BCPL o C ++. Muchos de estos ya se habían implementado como extensiones en varios compiladores de C.

C99 es en su mayor parte retrocompatible con C90, pero es más estricto en algunos aspectos; en particular, una declaración que carece de un especificador de tipo ya no se ha intasumido implícitamente. Una macro estándar __STDC_VERSION__se define con un valor 199901Lpara indicar que la compatibilidad con C99 está disponible. GCC , Solaris Studio y otros compiladores de C ahora admiten muchas o todas las nuevas funciones de C99. Sin embargo, el compilador de C en Microsoft Visual C ++ implementa el estándar C89 y las partes de C99 que son necesarias para la compatibilidad con C ++ 11 .

Además, ahora se requiere soporte para identificadores Unicode (nombres de variables / funciones) en forma de caracteres de escape (por ejemplo \U0001f431). El soporte para nombres Unicode sin formato es opcional.

C11

En 2007, se comenzó a trabajar en otra revisión del estándar C, informalmente llamado "C1X" hasta su publicación oficial el 2011-12-08. El comité de estándares C adoptó pautas para limitar la adopción de nuevas características que no habían sido probadas por implementaciones existentes.

El estándar C11 agrega numerosas características nuevas a C y la biblioteca, que incluyen macros genéricas de tipo, estructuras anónimas, compatibilidad mejorada con Unicode, operaciones atómicas, subprocesos múltiples y funciones de control de límites. También hace que algunas partes de la biblioteca C99 existente sean opcionales y mejora la compatibilidad con C ++. La macro estándar __STDC_VERSION__se define 201112Lpara indicar que el soporte C11 está disponible.

C17

Publicado en junio de 2018, C17 es el estándar actual para el lenguaje de programación C. No introduce nuevas características de lenguaje, solo correcciones técnicas y aclaraciones de defectos en C11. La macro estándar __STDC_VERSION__se define como 201710L.

C2x

C2x es un nombre informal para la próxima revisión principal del estándar del lenguaje C (después de C17). Se espera que se vote en 2023 y, por lo tanto, se llamaría C23.

C integrado

Históricamente, la programación C embebida requiere extensiones no estándar del lenguaje C para admitir características exóticas como aritmética de punto fijo, múltiples bancos de memoria distintos y operaciones básicas de E / S.

En 2008, el Comité de Estándares C publicó un informe técnico que amplía el lenguaje C para abordar estos problemas al proporcionar un estándar común al que deben adherirse todas las implementaciones. Incluye una serie de funciones que no están disponibles en C normal, como aritmética de punto fijo , espacios de direcciones con nombre y direccionamiento básico de hardware de E / S.

Sintaxis

C tiene una gramática formal especificada por el estándar C. Los finales de línea generalmente no son significativos en C; sin embargo, los límites de las líneas tienen importancia durante la fase de preprocesamiento. Los comentarios pueden aparecer entre los delimitadores /*y */, o (desde C99) a continuación //hasta el final de la línea. Los comentarios delimitados por /*y */no anidados, y estas secuencias de caracteres no se interpretan como delimitadores de comentarios si aparecen dentro de cadenas o caracteres literales.

Los archivos fuente C contienen declaraciones y definiciones de funciones. Las definiciones de funciones, a su vez, contienen declaraciones y declaraciones . Las declaraciones definen nuevos tipos usando palabras clave como struct, uniony enum, o asignan tipos y quizás reservan almacenamiento para nuevas variables, generalmente escribiendo el tipo seguido del nombre de la variable. Palabras clave como chary intespecifican tipos integrados. Las secciones de código se incluyen entre llaves ( {y }, a veces, llamadas "llaves") para limitar el alcance de las declaraciones y actuar como una sola declaración para las estructuras de control.

Como lenguaje imperativo, C usa declaraciones para especificar acciones. La declaración más común es una declaración de expresión , que consta de una expresión a evaluar, seguida de un punto y coma; como efecto secundario de la evaluación, se pueden llamar funciones y se pueden asignar nuevos valores a las variables . Para modificar la ejecución secuencial normal de declaraciones, C proporciona varias declaraciones de flujo de control identificadas por palabras clave reservadas. Programación estructurada es apoyado por if(- else) y por la ejecución condicional do- while, whiley forla ejecución iterativa (bucle). La fordeclaración tiene expresiones de inicialización, prueba y reinicialización separadas, cualquiera o todas las cuales se pueden omitir. breaky continuese puede usar para dejar la declaración de bucle de cierre más interna o saltar a su reinicialización. También hay una gotodeclaración no estructurada que se ramifica directamente a la etiqueta designada dentro de la función. switchselecciona casea que se ejecutará basándose en el valor de una expresión entera.

Las expresiones pueden usar una variedad de operadores integrados y pueden contener llamadas a funciones. El orden en el que se evalúan los argumentos de las funciones y los operandos de la mayoría de los operadores no está especificado. Las evaluaciones pueden incluso estar intercaladas. Sin embargo, todos los efectos secundarios (incluido el almacenamiento de variables) ocurrirán antes del siguiente " punto de secuencia "; los puntos de secuencia incluyen el final de cada declaración de expresión y la entrada y el retorno de cada llamada de función. También puntos de secuencia ocurren durante la evaluación de las expresiones que contienen ciertos operadores ( &&, ||, ?:y el operador de coma ). Esto permite un alto grado de optimización del código objeto por parte del compilador, pero requiere que los programadores de C tengan más cuidado para obtener resultados confiables que el necesario para otros lenguajes de programación.

Kernighan y Ritchie dicen en la Introducción del lenguaje de programación C : "C, como cualquier otro lenguaje, tiene sus defectos. Algunos de los operadores tienen una precedencia incorrecta; algunas partes de la sintaxis podrían ser mejores". El estándar C no intentó corregir muchas de estas imperfecciones, debido al impacto de tales cambios en el software ya existente.

Conjunto de caracteres

El conjunto básico de caracteres de origen C incluye los siguientes caracteres:

Newline indica el final de una línea de texto; no es necesario que corresponda a un solo carácter real, aunque, por conveniencia, C lo trata como uno.

Se pueden usar caracteres codificados de varios bytes adicionales en literales de cadena, pero no son completamente portátiles . El último estándar C ( C11 ) permite que los caracteres Unicode multinacionales se incrusten de forma portátil en el texto fuente de C mediante el uso \uXXXXo la \UXXXXXXXXcodificación (donde Xdenota un carácter hexadecimal), aunque esta función aún no está ampliamente implementada.

El conjunto de caracteres de ejecución básico de C contiene los mismos caracteres, junto con representaciones de alerta , retroceso y retorno de carro . El soporte en tiempo de ejecución para conjuntos de caracteres extendidos ha aumentado con cada revisión del estándar C.

Palabras reservadas

C89 tiene 32 palabras reservadas, también conocidas como palabras clave, que son las palabras que no se pueden usar para ningún otro propósito que no sea para el que están predefinidas:

C99 reservó cinco palabras más:

C11 reservó siete palabras más:

  • _Alignas
  • _Alignof
  • _Atomic
  • _Generic
  • _Noreturn
  • _Static_assert
  • _Thread_local

La mayoría de las palabras reservadas recientemente comienzan con un guión bajo seguido de una letra mayúscula, porque los identificadores de esa forma estaban previamente reservados por el estándar C para su uso solo en implementaciones. Dado que el código fuente del programa existente no debería haber estado usando estos identificadores, no se vería afectado cuando las implementaciones de C comenzaran a admitir estas extensiones del lenguaje de programación. Algunos encabezados estándar definen sinónimos más convenientes para identificadores subrayados. Anteriormente, el lenguaje incluía una palabra reservada llamada entry, pero rara vez se implementaba y ahora se ha eliminado como palabra reservada.

Operadores

C admite un amplio conjunto de operadores , que son símbolos que se utilizan dentro de una expresión para especificar las manipulaciones que se realizarán al evaluar esa expresión. C tiene operadores para:

C usa el operador =(usado en matemáticas para expresar igualdad) para indicar asignación, siguiendo el precedente de Fortran y PL / I , pero a diferencia de ALGOL y sus derivados. C usa el operador ==para probar la igualdad. La similitud entre estos dos operadores (asignación e igualdad) puede resultar en el uso accidental de uno en lugar del otro y, en muchos casos, el error no produce un mensaje de error (aunque algunos compiladores producen advertencias). Por ejemplo, la expresión condicional if (a == b + 1)podría escribirse erróneamente como if (a = b + 1), que se evaluará como verdadera si ano es cero después de la asignación.

La precedencia del operador C no siempre es intuitiva. Por ejemplo, el operador ==enlaza más estrechamente que (se ejecuta antes de) los operadores &(bit a bit AND) y |(bit a bit OR) en expresiones como x & 1 == 0, que debe escribirse como (x & 1) == 0si esa fuera la intención del codificador.

Ejemplo de "Hola, mundo"

"¡Hola Mundo!" programa de Brian Kernighan (1978)

El ejemplo de " hola, mundo ", que apareció en la primera edición de K&R , se ha convertido en el modelo para un programa introductorio en la mayoría de los libros de texto de programación. El programa imprime "hola, mundo" en la salida estándar , que suele ser un terminal o una pantalla.

La versión original era:

main()
{
    printf("hello, world\n");
}

Un programa de "hola, mundo" que cumple con los estándares es:

# include <stdio.h>

int main(void)
{
    printf("hello, world\n");
}

La primera línea del programa contiene una directiva de preprocesamiento , indicada por #include. Esto hace que el compilador reemplace esa línea con el texto completo del stdio.hencabezado estándar, que contiene declaraciones para funciones estándar de entrada y salida como printfy scanf. Los corchetes angulares que rodean stdio.hindican que stdio.hse encuentra usando una estrategia de búsqueda que prefiere los encabezados proporcionados con el compilador a otros encabezados que tienen el mismo nombre, en contraposición a las comillas dobles que generalmente incluyen archivos de encabezado locales o específicos del proyecto.

La siguiente línea indica que mainse está definiendo una función nombrada . La mainfunción tiene un propósito especial en los programas C; el entorno de tiempo de ejecución llama a la mainfunción para comenzar la ejecución del programa. El especificador de tipo intindica que el valor que se devuelve al invocador (en este caso, el entorno de tiempo de ejecución) como resultado de la evaluación de la mainfunción, es un número entero. La palabra clave voidcomo lista de parámetros indica que esta función no acepta argumentos.

La llave de apertura indica el comienzo de la definición de la mainfunción.

La siguiente línea llama (desvía la ejecución a) una función nombrada printf, que en este caso se suministra desde una biblioteca del sistema . En esta llamada, a la printffunción se le pasa (se le proporciona) un único argumento, la dirección del primer carácter en la cadena literal "hello, world\n" . El literal de cadena es una matriz sin nombre con elementos de tipo char, configurada automáticamente por el compilador con un carácter final con valor 0 para marcar el final de la matriz ( printfnecesita saber esto). El \nes una secuencia de escape que C se traduce en una nueva línea de caracteres, que en la salida significa el final de la línea actual. El valor de retorno de la printffunción es de tipo int, pero se descarta silenciosamente ya que no se usa. (Un programa más cuidadoso podría probar el valor de retorno para determinar si la printffunción tuvo éxito o no ). El punto y coma ;termina la instrucción.

La llave de cierre indica el final del código de la mainfunción. De acuerdo con la especificación C99 y más reciente, la mainfunción, a diferencia de cualquier otra función, devolverá implícitamente un valor de 0al alcanzar el }que termina la función. (Antes return 0;se requería una declaración explícita ). Esto es interpretado por el sistema de tiempo de ejecución como un código de salida que indica una ejecución exitosa.

Tipos de datos

El sistema de tipos en C es estático y de tipo débil , lo que lo hace similar al sistema de tipos de los descendientes de ALGOL como Pascal . Hay tipos integrados para números enteros de varios tamaños, tanto con signo como sin signo, números de punto flotante y tipos enumerados ( enum). El tipo entero charse usa a menudo para caracteres de un solo byte. C99 agregó un tipo de datos booleano . También hay tipos derivados que incluyen matrices , punteros , registros ( struct) y uniones ( union).

C se utiliza a menudo en la programación de sistemas de bajo nivel donde puede ser necesario escapar del sistema de tipos. El compilador intenta garantizar la corrección de tipos de la mayoría de las expresiones, pero el programador puede anular las comprobaciones de varias formas, ya sea utilizando una conversión de tipos para convertir explícitamente un valor de un tipo a otro, o utilizando punteros o uniones para reinterpretar los bits subyacentes. de un objeto de datos de alguna otra manera.

Algunos encuentran la sintaxis de declaración de C poco intuitiva, particularmente para punteros de función . (La idea de Ritchie era declarar identificadores en contextos similares a su uso: "la declaración refleja el uso ").

Las conversiones aritméticas habituales de C permiten generar código eficiente, pero a veces pueden producir resultados inesperados. Por ejemplo, una comparación de enteros con y sin signo de igual ancho requiere una conversión del valor con signo a sin signo. Esto puede generar resultados inesperados si el valor con signo es negativo.

Punteros

C admite el uso de punteros , un tipo de referencia que registra la dirección o ubicación de un objeto o función en la memoria. Los punteros se pueden desreferenciar para acceder a los datos almacenados en la dirección apuntada, o para invocar una función apuntada. Los punteros se pueden manipular mediante asignación o aritmética de punteros . La representación en tiempo de ejecución de un valor de puntero es típicamente una dirección de memoria sin procesar (quizás aumentada por un campo de desplazamiento dentro de la palabra), pero dado que el tipo de un puntero incluye el tipo de la cosa apuntada, las expresiones que incluyen punteros se pueden verificar de tipo en tiempo de compilación. La aritmética de punteros se escala automáticamente según el tamaño del tipo de datos apuntado. Los punteros se usan para muchos propósitos en C. Las cadenas de texto se manipulan comúnmente usando punteros en matrices de caracteres. La asignación de memoria dinámica se realiza mediante punteros. Muchos tipos de datos, como árboles , se implementan comúnmente como structobjetos asignados dinámicamente vinculados entre sí mediante punteros. Los punteros a funciones son útiles para pasar funciones como argumentos a funciones de orden superior (como qsort o bsearch ) o como devoluciones de llamada para ser invocadas por controladores de eventos.

Un puntero nulo valor apunta explícitamente a ninguna ubicación válida. Desreferenciar un valor de puntero nulo no está definido, lo que a menudo resulta en un error de segmentación . Los valores de puntero nulos son útiles para indicar casos especiales como que no hay puntero "siguiente" en el nodo final de una lista vinculada , o como una indicación de error de funciones que devuelven punteros. En contextos apropiados en el código fuente, como para asignar a una variable de puntero, una constante de puntero nulo se puede escribir como 0, con o sin conversión explícita a un tipo de puntero, o como la NULLmacro definida por varios encabezados estándar. En contextos condicionales, los valores de puntero nulo se evalúan como falso, mientras que todos los demás valores de puntero se evalúan como verdadero.

Los punteros vacíos ( void *) apuntan a objetos de tipo no especificado y, por lo tanto, se pueden utilizar como punteros de datos "genéricos". Dado que no se conocen el tamaño y el tipo del objeto al que se apunta, los punteros vacíos no se pueden desreferenciar, ni se permite la aritmética de punteros en ellos, aunque pueden convertirse fácilmente (y en muchos contextos lo son implícitamente) desde y hacia cualquier otro puntero de objeto. escribe.

El uso descuidado de los indicadores es potencialmente peligroso. Debido a que normalmente no están marcadas, se puede hacer que una variable de puntero apunte a cualquier ubicación arbitraria, lo que puede causar efectos no deseados. Aunque los punteros correctamente utilizados apuntan a lugares seguros, se pueden hacer que apunten a lugares inseguros mediante el uso de aritmética de punteros no válidos ; los objetos a los que apuntan pueden seguir utilizándose después de la desasignación ( punteros colgantes ); se pueden utilizar sin haber sido inicializados ( punteros salvajes ); o se les puede asignar directamente un valor inseguro mediante un reparto, unión o mediante otro puntero corrupto. En general, C es permisivo al permitir la manipulación y conversión entre tipos de punteros, aunque los compiladores suelen proporcionar opciones para varios niveles de verificación. Algunos otros lenguajes de programación abordan estos problemas utilizando tipos de referencia más restrictivos .

Matrices

Los tipos de matriz en C son tradicionalmente de un tamaño fijo y estático especificado en el momento de la compilación. (El estándar C99 más reciente también permite una forma de matrices de longitud variable). Sin embargo, también es posible asignar un bloque de memoria (de tamaño arbitrario) en tiempo de ejecución, utilizando la mallocfunción de la biblioteca estándar , y tratarlo como un formación. La unificación de matrices y punteros de C significa que las matrices declaradas y estas matrices simuladas asignadas dinámicamente son virtualmente intercambiables.

Dado que siempre se accede a las matrices (en efecto) a través de punteros, los accesos a las matrices normalmente no se comparan con el tamaño de la matriz subyacente, aunque algunos compiladores pueden proporcionar la verificación de límites como una opción. Por lo tanto, las violaciones de los límites de la matriz son posibles y bastante comunes en el código escrito de manera descuidada, y pueden tener varias repercusiones, incluidos los accesos ilegales a la memoria, la corrupción de datos, los desbordamientos del búfer y las excepciones en tiempo de ejecución. Si se desea la verificación de límites, se debe realizar manualmente.

C no tiene una disposición especial para declarar matrices multidimensionales , sino que se basa en la recursividad dentro del sistema de tipos para declarar matrices de matrices, lo que efectivamente logra lo mismo. Se puede pensar que los valores de índice de la "matriz multidimensional" resultante aumentan en orden de fila principal .

Las matrices multidimensionales se utilizan comúnmente en algoritmos numéricos (principalmente de álgebra lineal aplicada ) para almacenar matrices. La estructura de la matriz C se adapta bien a esta tarea en particular. Sin embargo, dado que las matrices se pasan simplemente como punteros, los límites de la matriz deben ser valores fijos conocidos o bien pasados ​​explícitamente a cualquier subrutina que los requiera, y no se puede acceder a matrices de matrices de tamaño dinámico mediante la indexación doble. (Una solución para esto es asignar la matriz con un "vector de fila" adicional de punteros a las columnas).

C99 introdujo "matrices de longitud variable" que abordan algunos, pero no todos, los problemas de las matrices C ordinarias.

Intercambiabilidad de matriz-puntero

La notación de subíndice x[i](donde xdesigna un puntero) es azúcar sintáctica para *(x+i). Aprovechando el conocimiento del compilador del tipo de puntero, la dirección a la que x + iapunta no es la dirección base (apuntada por x) incrementada en ibytes, sino que se define como la dirección base incrementada por imultiplicada por el tamaño de un elemento que xapunta para. Por lo tanto, x[i]designa el i+1th elemento de la matriz.

Además, en la mayoría de los contextos de expresión (una excepción notable es como operando de sizeof), el nombre de una matriz se convierte automáticamente en un puntero al primer elemento de la matriz. Esto implica que una matriz nunca se copia como un todo cuando se nombra como un argumento de una función, sino que solo se pasa la dirección de su primer elemento. Por lo tanto, aunque las llamadas a funciones en C usan semántica de paso por valor , las matrices se pasan de hecho por referencia .

El tamaño de un elemento se puede determinar aplicando el operador sizeofa cualquier elemento desreferenciado de x, como en n = sizeof *xo n = sizeof x[0], y el número de elementos en una matriz declarada Ase puede determinar como sizeof A / sizeof A[0]. Esto último solo se aplica a los nombres de matrices: variables declaradas con subíndices ( int A[20]). Debido a la semántica de C, no es posible determinar el tamaño completo de matrices a través de punteros a matrices, como matrices creadas por asignación dinámica ( malloc) o parámetros de función de matriz; código como sizeof arr / sizeof arr[0](donde arrdesigna un puntero) no funcionará ya que el compilador asume que se está solicitando el tamaño del puntero. Dado que los argumentos de los nombres de la matriz sizeofno se convierten en punteros, no presentan tal ambigüedad. Sin embargo, se accede a las matrices creadas por asignación dinámica mediante punteros en lugar de variables de matriz verdaderas, por lo que sufren los mismos sizeofproblemas que los punteros de matriz.

Por lo tanto, a pesar de esta aparente equivalencia entre las variables de matriz y de puntero, todavía hay que hacer una distinción entre ellas. Aunque el nombre de una matriz, en la mayoría de los contextos de expresión, se convierte en un puntero (a su primer elemento), este puntero no ocupa en sí mismo ningún almacenamiento; el nombre de la matriz no es un valor l , y su dirección es una constante, a diferencia de una variable de puntero. En consecuencia, lo que una matriz "apunta" no se puede cambiar y es imposible asignar una nueva dirección a un nombre de matriz. Sin embargo, el contenido de la matriz se puede copiar utilizando la memcpyfunción o accediendo a los elementos individuales.

Gestión de la memoria

Una de las funciones más importantes de un lenguaje de programación es proporcionar facilidades para administrar la memoria y los objetos que se almacenan en la memoria. C proporciona tres formas distintas de asignar memoria para objetos:

  • Asignación de memoria estática : el espacio para el objeto se proporciona en el binario en tiempo de compilación; estos objetos tienen una extensión (o duración) siempre que el binario que los contiene se cargue en la memoria.
  • Asignación automática de memoria : los objetos temporales se pueden almacenar en la pila , y este espacio se libera automáticamente y se reutiliza después de que se sale del bloque en el que están declarados.
  • Asignación dinámica de memoria : se pueden solicitar bloques de memoria de tamaño arbitrario en tiempo de ejecución utilizando funciones de biblioteca como, por ejemplo, mallocde una región de memoria llamada montón ; estos bloques persisten hasta que posteriormente se liberan para su reutilización llamando a la función de biblioteca reallocofree

Estos tres enfoques son apropiados en diferentes situaciones y tienen varias compensaciones. Por ejemplo, la asignación de memoria estática tiene poca sobrecarga de asignación, la asignación automática puede implicar un poco más de sobrecarga y la asignación de memoria dinámica puede tener potencialmente una gran sobrecarga tanto para la asignación como para la desasignación. La naturaleza persistente de los objetos estáticos es útil para mantener la información de estado en todas las llamadas a funciones, la asignación automática es fácil de usar, pero el espacio de pila suele ser mucho más limitado y transitorio que la memoria estática o el espacio de pila, y la asignación de memoria dinámica permite la asignación conveniente de objetos cuya el tamaño solo se conoce en tiempo de ejecución. La mayoría de los programas en C hacen un uso extensivo de los tres.

Cuando es posible, la asignación automática o estática suele ser más simple porque el almacenamiento lo administra el compilador, lo que libera al programador de la tarea potencialmente propensa a errores de asignar y liberar manualmente el almacenamiento. Sin embargo, muchas estructuras de datos pueden cambiar de tamaño en tiempo de ejecución, y dado que las asignaciones estáticas (y las asignaciones automáticas antes de C99) deben tener un tamaño fijo en tiempo de compilación, hay muchas situaciones en las que es necesaria la asignación dinámica. Antes del estándar C99, las matrices de tamaño variable eran un ejemplo común de esto. (Consulte el artículo sobre mallocpara ver un ejemplo de matrices asignadas dinámicamente). A diferencia de la asignación automática, que puede fallar en tiempo de ejecución con consecuencias no controladas, las funciones de asignación dinámica devuelven una indicación (en forma de un valor de puntero nulo) cuando el almacenamiento requerido no puede ser asignado. (La asignación estática que es demasiado grande generalmente es detectada por el vinculador o el cargador , antes de que el programa pueda siquiera comenzar la ejecución).

A menos que se especifique lo contrario, los objetos estáticos contienen valores de puntero cero o nulos al iniciar el programa. Los objetos asignados automática y dinámicamente se inicializan solo si se especifica explícitamente un valor inicial; de lo contrario, inicialmente tienen valores indeterminados (normalmente, cualquier patrón de bits que esté presente en el almacenamiento , que puede que ni siquiera represente un valor válido para ese tipo). Si el programa intenta acceder a un valor no inicializado, los resultados no están definidos. Muchos compiladores modernos intentan detectar y advertir sobre este problema, pero pueden producirse tanto falsos positivos como falsos negativos .

La asignación de memoria del montón debe sincronizarse con su uso real en cualquier programa para poder reutilizarla tanto como sea posible. Por ejemplo, si el único puntero a una asignación de memoria del montón sale del alcance o se sobrescribe su valor antes de que se desasigne explícitamente, entonces esa memoria no se puede recuperar para su posterior reutilización y esencialmente se pierde en el programa, un fenómeno conocido como memoria. fuga . Por el contrario, es posible que se libere la memoria, pero se hace referencia a ella posteriormente, lo que da lugar a resultados impredecibles. Por lo general, los síntomas de falla aparecen en una parte del programa que no está relacionada con el código que causa el error, lo que dificulta el diagnóstico de la falla. Estos problemas se mejoran en lenguajes con recolección automática de basura .

Bibliotecas

El lenguaje de programación C usa bibliotecas como su método principal de extensión. En C, una biblioteca es un conjunto de funciones contenidas en un solo archivo "archivo". Cada biblioteca tiene típicamente un archivo de encabezado , que contiene los prototipos de las funciones contenidas dentro de la biblioteca que pueden ser usadas por un programa, y ​​declaraciones de tipos de datos especiales y macro símbolos usados ​​con estas funciones. Para que un programa use una biblioteca, debe incluir el archivo de encabezado de la biblioteca y la biblioteca debe estar vinculada con el programa, que en muchos casos requiere indicadores del compilador (p. Ej. -lm, Abreviatura de "vincular la biblioteca matemática").

La biblioteca C más común es la biblioteca estándar C , que está especificada por los estándares ISO y ANSI C y viene con cada implementación de C (las implementaciones que se dirigen a entornos limitados, como los sistemas integrados, pueden proporcionar solo un subconjunto de la biblioteca estándar). Esta biblioteca admite entrada y salida de flujo, asignación de memoria, matemáticas, cadenas de caracteres y valores de tiempo. Varios encabezados estándar separados (por ejemplo, stdio.h) especifican las interfaces para estos y otros recursos de biblioteca estándar.

Otro conjunto común de funciones de biblioteca C son los utilizados por las aplicaciones dirigidas específicamente para Unix y Unix-como sistemas, especialmente funciones que proporcionan una interfaz para el kernel . Estas funciones se detallan en varios estándares como POSIX y la Especificación Única de UNIX .

Dado que muchos programas se han escrito en C, existe una amplia variedad de otras bibliotecas disponibles. Las bibliotecas a menudo se escriben en C porque los compiladores de C generan un código objeto eficiente ; Luego, los programadores crean interfaces para la biblioteca para que las rutinas se puedan usar desde lenguajes de nivel superior como Java , Perl y Python .

Manejo de archivos y flujos

La entrada y salida de archivos (E / S) no es parte del lenguaje C en sí, sino que es manejada por bibliotecas (como la biblioteca estándar de C) y sus archivos de encabezado asociados (por ejemplo stdio.h). El manejo de archivos generalmente se implementa a través de E / S de alto nivel que funciona a través de flujos . Desde esta perspectiva, un flujo es un flujo de datos que es independiente de los dispositivos, mientras que un archivo es un dispositivo concreto. La E / S de alto nivel se realiza mediante la asociación de una secuencia a un archivo. En la biblioteca estándar de C, un búfer (un área de memoria o cola) se usa temporalmente para almacenar datos antes de enviarlos al destino final. Esto reduce el tiempo de espera por dispositivos más lentos, por ejemplo, un disco duro o una unidad de estado sólido . Las funciones de E / S de bajo nivel no forman parte de la biblioteca C estándar, pero generalmente forman parte de la programación "básica" (programación que es independiente de cualquier sistema operativo , como la mayoría de la programación integrada ). Con pocas excepciones, las implementaciones incluyen E / S de bajo nivel.

Herramientas del lenguaje

Se han desarrollado varias herramientas para ayudar a los programadores de C a encontrar y corregir declaraciones con comportamiento indefinido o expresiones posiblemente erróneas, con mayor rigor que el proporcionado por el compilador. La pelusa de la herramienta fue la primera de ellas, lo que dio lugar a muchas otras.

La verificación y auditoría de código fuente automatizadas son beneficiosas en cualquier idioma, y ​​para C existen muchas herramientas de este tipo, como Lint . Una práctica común es usar Lint para detectar código cuestionable cuando se escribe un programa por primera vez. Una vez que un programa pasa Lint, se compila utilizando el compilador de C. Además, muchos compiladores pueden advertir opcionalmente sobre construcciones sintácticamente válidas que probablemente sean errores. MISRA C es un conjunto de pautas patentado para evitar este tipo de código cuestionable, desarrollado para sistemas embebidos.

También hay compiladores, bibliotecas y mecanismos de nivel de sistema operativo para realizar acciones que no son una parte estándar de C, como la verificación de límites para matrices, detección de desbordamiento de búfer , serialización , seguimiento dinámico de memoria y recolección automática de basura .

Herramientas como Purify o Valgrind y la vinculación con bibliotecas que contienen versiones especiales de las funciones de asignación de memoria pueden ayudar a descubrir errores de tiempo de ejecución en el uso de la memoria.

Usos

El gráfico de índice TIOBE , que muestra una comparación de la popularidad de varios lenguajes de programación.

C se usa ampliamente para la programación de sistemas en la implementación de sistemas operativos y aplicaciones de sistemas embebidos , porque el código C, cuando se escribe para la portabilidad, se puede usar para la mayoría de los propósitos; sin embargo, cuando es necesario, el código específico del sistema se puede usar para acceder a direcciones de hardware específicas y para realizar el tipo juego de palabras para que coincida con los requisitos de interfaz impuestas desde el exterior, la mínima de tiempo de ejecución de la demanda de recursos del sistema.

C se puede utilizar para la programación de sitios web utilizando Common Gateway Interface (CGI) como una "puerta de enlace" para la información entre la aplicación web, el servidor y el navegador. C a menudo se elige sobre los idiomas interpretados debido a su velocidad, estabilidad y disponibilidad casi universal.

Una consecuencia de la amplia disponibilidad y eficiencia de C es que los compiladores , bibliotecas e intérpretes de otros lenguajes de programación a menudo se implementan en C. Por ejemplo, las implementaciones de referencia de Python , Perl , Ruby y PHP están escritas en C.

C permite a los programadores crear implementaciones eficientes de algoritmos y estructuras de datos, debido a que la capa de abstracción del hardware es delgada y su sobrecarga es baja, un criterio importante para los programas computacionalmente intensivos. Por ejemplo, la biblioteca aritmética de precisión múltiple GNU , la biblioteca científica GNU , Mathematica y MATLAB están completa o parcialmente escritas en C.

A veces, C se utiliza como lenguaje intermedio mediante implementaciones de otros lenguajes. Este enfoque se puede utilizar por motivos de portabilidad o conveniencia; al utilizar C como lenguaje intermedio, no son necesarios generadores de código específicos de la máquina adicionales. C tiene algunas características, como directivas de preprocesador de número de línea y comas superfluas opcionales al final de las listas de inicializadores, que admiten la compilación del código generado. Sin embargo, algunas de las deficiencias de C han impulsado el desarrollo de otros lenguajes basados ​​en C diseñados específicamente para su uso como lenguajes intermedios, como C-- .

C también se ha utilizado ampliamente para implementar aplicaciones de usuario final . Sin embargo, estas aplicaciones también se pueden escribir en lenguajes más nuevos y de alto nivel.

Idiomas relacionados

C ha influido tanto directa como indirectamente en muchos lenguajes posteriores como C # , D , Go , Java , JavaScript , Limbo , LPC , Perl , PHP , Python y el shell C de Unix . La influencia más penetrante ha sido sintáctica; todos los lenguajes mencionados combinan la sintaxis de enunciado y expresión (más o menos reconocible) de C con sistemas de tipos, modelos de datos y / o estructuras de programas a gran escala que difieren de las de C, a veces radicalmente.

Existen varios intérpretes de C o near-C, incluidos Ch y CINT , que también se pueden utilizar para secuencias de comandos.

Cuando los lenguajes orientados a objetos se hicieron populares, C ++ y Objective-C eran dos extensiones diferentes de C que proporcionaban capacidades orientadas a objetos. Ambos lenguajes se implementaron originalmente como compiladores de fuente a fuente ; el código fuente se tradujo a C y luego se compiló con un compilador de C.

El lenguaje de programación C ++ fue diseñado por Bjarne Stroustrup como un enfoque para proporcionar funcionalidad orientada a objetos con una sintaxis similar a C. C ++ agrega mayor fuerza de escritura, alcance y otras herramientas útiles en la programación orientada a objetos, y permite la programación genérica a través de plantillas. Casi un superconjunto de C, C ++ ahora admite la mayor parte de C, con algunas excepciones .

Objective-C era originalmente una capa muy "fina" encima de C, y sigue siendo un superconjunto estricto de C que permite la programación orientada a objetos utilizando un paradigma híbrido de tipado dinámico / estático. Objective-C deriva su sintaxis tanto de C como de Smalltalk : la sintaxis que implica preprocesamiento, expresiones, declaraciones de funciones y llamadas a funciones se hereda de C, mientras que la sintaxis de las características orientadas a objetos se tomó originalmente de Smalltalk.

Además de C ++ y Objective-C , Ch , Cilk y Unified Parallel C son casi superconjuntos de C.

Ver también

Notas

Referencias

Fuentes

Otras lecturas

enlaces externos