C (lenguaje de programación)

Lenguaje de programación de propósito general

do
El texto dice "El lenguaje de programación C"
Logotipo utilizado en la portada de la primera edición de The C Programming Language [1]
ParadigmaMultiparadigma : imperativo ( procedimental ), estructurado
Diseñado porDennis Ritchie
ReveladorANSI X3J11 ( ANSI C ); ISO/IEC JTC 1 (Comité Técnico Conjunto 1) / SC 22 (Subcomité 22) / WG 14 (Grupo de Trabajo 14) (ISO C)
Apareció por primera vez1972 ; hace 52 años [2] ( 1972 )
Versión estable
C23 / 31 de octubre de 2024 ; hace 18 días ( 31/10/2024 )
Versión preliminar
C2y (N3220) / 21 de febrero de 2024 ; hace 8 meses [3] ( 21-02-2024 )
Disciplina de mecanografíaEstático , débil , manifiesto , nominal
Sistema operativoMultiplataforma
Extensiones de nombre de archivo.c, .h
Sitio webwww.iso.org/standard/82075.html
www.open-std.org/jtc1/sc22/wg14/
Implementaciones principales
pcc , GCC , Clang , Intel C , C++Builder , Microsoft Visual C++ , Watcom C
Dialectos
Ciclón , Paralelo Unificado C , Split-C , Cilk , C*
Influenciado por
B ( BCPL , CPL ), ALGOL 68 , [4] PL/I , FORTRAN
Influenciado
Numerosos : AMPL , AWK , csh , C++ , C-- , C# , Objective-C , D , Go , Java , JavaScript , JS++ , Julia , Limbo , LPC , Perl , PHP , Pike , Processing , Python , Rust , Seed7 , V (Vlang) , Vala , Verilog (HDL), [5] Nim , Zig
  • Programación en C en Wikilibros

C ( pronunciado / ˈs / como la letra c ) [6] es un lenguaje de programación de propósito general . Fue creado en la década de 1970 por Dennis Ritchie y sigue siendo muy utilizado e influyente. Por diseño, las características de C reflejan claramente las capacidades de las CPU de destino. Ha encontrado un uso duradero en el código de sistemas operativos (especialmente en kernels [7] ), controladores de dispositivos y pilas de protocolos , pero su uso en software de aplicación ha ido disminuyendo. [8] C se usa comúnmente en arquitecturas de computadoras que van desde las supercomputadoras más grandes hasta los microcontroladores y sistemas integrados más pequeños .

Un sucesor del lenguaje de programación B , C fue desarrollado originalmente en Bell Labs por Ritchie entre 1972 y 1973 para construir utilidades que se ejecutaban en Unix . Se aplicó para reimplementar el núcleo del sistema operativo Unix. [9] Durante la década de 1980, C ganó popularidad gradualmente. Se ha convertido en uno de los lenguajes de programación más utilizados, [10] [11] con compiladores de C disponibles para prácticamente todas las arquitecturas informáticas y sistemas operativos modernos. El libro The C Programming Language , coescrito por el diseñador original del lenguaje, sirvió durante muchos años como el estándar de facto para el lenguaje. [12] [1] C ha sido estandarizado desde 1989 por el American National Standards Institute (ANSI) y, posteriormente, conjuntamente por la Organización Internacional de Normalización (ISO) y la Comisión Electrotécnica Internacional (IEC).

C es un lenguaje procedimental imperativo , compatible con programación estructurada , alcance de variable léxica y recursión , con un sistema de tipos estático . Fue diseñado para ser compilado para proporcionar acceso de bajo nivel a la memoria y construcciones de lenguaje que se asignan de manera eficiente a instrucciones de máquina , todo con un soporte mínimo en 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 estándares escrito con la portabilidad en mente se puede compilar para una amplia variedad de plataformas informáticas y sistemas operativos con pocos cambios en su código fuente.

Desde el año 2000, C se ha situado constantemente entre los cuatro primeros lenguajes en el índice TIOBE , una medida de la popularidad de los lenguajes de programación. [13]

Descripción general

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

C es un lenguaje imperativo y procedimental en la tradición ALGOL . Tiene un sistema de tipos estático . En C, todo el código ejecutable está contenido dentro de subrutinas (también llamadas "funciones", aunque no en el sentido de programación funcional ). Los parámetros de función se pasan por valor, aunque las matrices se pasan como punteros , es decir, la dirección del primer elemento de la matriz. El paso por referencia se simula en C al pasar explícitamente punteros al elemento al que se hace referencia.

El texto fuente del programa C es un código de formato libre . Los puntos y comas terminan las sentencias , mientras que las llaves se utilizan para agrupar sentencias en bloques .

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

  • El lenguaje tiene una cantidad pequeña y fija de palabras clave, incluido un conjunto completo de primitivas de flujo de controlif/else : , for, do/while, whiley switch. Los nombres definidos por el usuario no se distinguen de las palabras clave por ningún tipo de sigilo .
  • Tiene una gran cantidad de operadores aritméticos, bit a bit y lógicos: +, +=, ++, &, ||, etc.
  • Se podrá realizar más de una tarea en una sola declaración.
  • Funciones:
    • Los valores de retorno de la función se pueden ignorar cuando no sean necesarios.
    • Los punteros de funciones y datos permiten un polimorfismo en tiempo de ejecución ad hoc .
    • Las funciones no pueden definirse dentro del ámbito léxico de otras funciones.
    • Las variables se pueden definir dentro de una función, con alcance .
    • Una función puede llamarse a sí misma, por lo que se admite la recursión .
  • La tipificación de datos es estática , pero débilmente aplicada ; todos los datos tienen un tipo, pero son posibles las conversiones implícitas .
  • Son posibles tipos definidos por el usuario ( typedef ) y compuestos.
    • Los tipos de datos agregados heterogéneos ( struct) permiten acceder a elementos de datos relacionados y asignarlos como una unidad. El contenido de estructuras completas no se puede comparar utilizando un único operador integrado (los elementos se deben comparar individualmente).
    • La unión es una estructura con miembros superpuestos; permite que múltiples tipos de datos compartan la misma ubicación de memoria.
    • La indexación de matrices es una notación secundaria, definida en términos de aritmética de punteros. No se pueden asignar ni comparar matrices completas utilizando un único operador integrado. No se utiliza ni se define la palabra clave "matriz"; en su lugar, los corchetes indican matrices sintácticamente, por ejemplo month[11].
    • Los tipos enumerados son posibles con la enumpalabra clave. Se pueden convertir libremente con números enteros.
    • Las cadenas no son un tipo de datos distinto, sino que 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 la máquina en punteros .
  • Los procedimientos (subrutinas que no devuelven valores) son un caso especial de función, con un tipo de retorno vacío void.
  • Se puede asignar memoria a un programa con llamadas a rutinas de biblioteca .
  • Un preprocesador realiza la definición de macro , 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 vincular entre sí, con control sobre qué funciones y objetos de datos son visibles para otros archivos a través de atributos staticy extern.
  • Las funciones complejas como E/S , manipulación de cadenas y funciones matemáticas se delegan consistentemente a rutinas de biblioteca .
  • El código generado después de la compilación tiene necesidades relativamente sencillas en la plataforma subyacente, lo que lo hace adecuado para crear sistemas operativos y para su uso en sistemas integrados .

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, el sistema de objetos GLib o el recolector de basura Boehm ).

Relaciones con otros idiomas

Muchos lenguajes posteriores han tomado prestado directa o indirectamente de C, incluyendo C++ , C# , C shell de Unix , D , Go , Java , JavaScript (incluyendo transpiladores ), Julia , Limbo , LPC , Objective-C , Perl , PHP , Python , Ruby , Rust , Swift , Verilog y SystemVerilog (lenguajes de descripción de hardware). [5] Estos lenguajes han tomado muchas de sus estructuras de control y otras características básicas de C. La mayoría de ellos también expresan una sintaxis muy similar a C, y tienden a combinar la sintaxis reconocible de expresión y declaración de C con sistemas de tipos subyacentes, modelos de datos y semántica que pueden ser radicalmente diferentes.

Historia

Primeros desarrollos

Cronología del lenguaje C
Año
Nombre informal

Norma oficial
1972primer lanzamiento
1978K&R C
1989,
1990
Normas ANSI C89,
ISO C90
ANSI X3.159-1989
ISO/IEC 9899:1990
1999C99 , C9XISO/IEC 9899:1999
2011C11 , C1XISO/IEC 9899:2011
2018C17 , C18ISO/IEC 9899:2018
2024C23 , C2XISO/IEC 9899:2024
FuturoC2Y

El origen de C está estrechamente ligado al desarrollo del sistema operativo Unix , implementado originalmente 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 original PDP-11 de Unix también se desarrolló en lenguaje ensamblador. [9]

B

Thompson quería un lenguaje de programación para desarrollar utilidades para la nueva plataforma. Primero intentó escribir un compilador Fortran , pero pronto abandonó la idea y en su lugar creó una versión reducida del lenguaje de programación de sistemas recientemente desarrollado llamado BCPL . La descripción oficial de BCPL no estaba disponible en ese momento, [14] y Thompson modificó la sintaxis para que fuera menos "prolija" y similar a un ALGOL simplificado conocido como SMALGOL. [15] Llamó al resultado B , [9] describiéndolo como "semántica BCPL con mucha sintaxis SMALGOL". [15] Al igual que BCPL, B tenía un compilador de arranque para facilitar la portabilidad a nuevas máquinas. [15] En última instancia, se escribieron pocas utilidades en B porque era demasiado lento y no podía aprovechar las características de PDP-11 como la direccionabilidad de bytes .

Nuevo lanzamiento de B y primer lanzamiento de C

En 1971, Ritchie comenzó a mejorar B para utilizar las características del más potente PDP-11. Una adición significativa fue un tipo de datos de carácter, al que llamó New B (NB). [15] Thompson comenzó a utilizar NB para escribir el núcleo de Unix , y sus requisitos dieron forma a la dirección del desarrollo del lenguaje. [15] [16] Hasta 1972, se añadieron tipos más ricos al lenguaje NB: NB tenía matrices de inty char. También se añadieron punteros, la capacidad de generar punteros a otros tipos, matrices de todos los tipos y tipos que se devolverían desde funciones. Las matrices dentro de expresiones se convirtieron en punteros. Se escribió un nuevo compilador y el lenguaje pasó a llamarse C. [9]

El compilador de C y algunas utilidades creadas con él se incluyeron en la versión 2 de Unix , también conocida como Research Unix . [17]

Estructuras y reescritura del kernel de Unix

En la versión 4 de Unix , lanzada en noviembre de 1973, el núcleo de Unix fue ampliamente reimplementado en C. [9] En ese momento, 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 de cadenas simples: #includey #definede macros 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 . [9]

Unix fue uno de los primeros núcleos de sistemas operativos implementados en un lenguaje distinto del ensamblador . Ejemplos anteriores incluyen el sistema Multics (que fue escrito en PL/I ) y el Programa de Control Maestro (MCP) para el Burroughs B5000 (que fue escrito en ALGOL ) en 1961. Alrededor de 1977, Ritchie y Stephen C. Johnson realizaron más cambios al 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. [16]

K&R C

La portada del libro El lenguaje de programación C , 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 . [18] Conocido como K&R por las iniciales de sus autores, el libro 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 publicó en 1978, ahora también se conoce como C78 . [19] La segunda edición del libro [20] cubre el estándar ANSI C posterior , que se describe a continuación.

K&R introdujo varias características del lenguaje:

  • Biblioteca de E/S estándar
  • long inttipo de datos
  • unsigned inttipo de datos
  • Los operadores de asignación compuestos 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ían interpretado como (decrementar en 10) en lugar del posiblemente previsto ( 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 se restringieron los programadores de C cuando se deseaba la máxima portabilidad, ya que muchos compiladores antiguos todavía estaban en uso y porque el código K&R C cuidadosamente escrito también puede ser estándar C legal.

En las primeras versiones de C, solo las funciones que devuelven tipos distintos de intdebían declararse si se utilizaban 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 (); /* Esta es una declaración de función, por lo que el compilador puede conocer el nombre y el tipo de retorno de esta función. */ /* int */ other_function (); /* Otra declaración de función. Debido a que esta es una versión temprana de C, hay un tipo 'int' implícito aquí. Un comentario muestra dónde se requeriría el especificador de tipo 'int' explícito en versiones posteriores. */    /* int */ calling_function () /* Esta es una definición de función, que incluye el cuerpo del código que sigue entre las { llaves }. Debido a que no se especifica ningún tipo de retorno, la función retorna implícitamente un 'int' en esta versión temprana de C. */ { long test1 ; register /* int */ test2 ; /* Nuevamente, note que 'int' no es requerido aquí. El especificador de tipo 'int' */ /* en el comentario sería requerido en versiones posteriores de C. */ /* La palabra clave 'register' indica al compilador que esta variable debería */ /* almacenarse idealmente en un registro en lugar de dentro del marco de la pila. */ test1 = some_function (); if ( test1 > 1 ) test2 = 0 ; else test2 = other_function (); return test2 ; }                           

Los intespecificadores de tipo que están comentados podrían omitirse en K&R C, pero son necesarios en estándares posteriores.

Dado que las declaraciones de funciones de K&R no incluían ninguna información sobre los argumentos de la función, no se realizaban comprobaciones de tipo de los parámetros de la función, aunque algunos compiladores emitían un mensaje de advertencia si se llamaba a una función local con una cantidad incorrecta de argumentos o si diferentes llamadas a una función externa utilizaban diferentes cantidades 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 fuente.

En los años posteriores a la publicación de K&R C, se añadieron varias características al lenguaje, respaldadas por compiladores de AT&T (en particular PCC [21] ) y otros proveedores. Entre ellas se incluyen:

  • voidfunciones (es decir, funciones sin valor de retorno)
  • Funciones que devuelven structo uniontipos (anteriormente solo se podía devolver un único puntero, entero o flotante)
  • Asignación para structtipos de datos
  • tipos enumerados (anteriormente, se utilizaban definiciones de preprocesador para valores fijos enteros, por ejemplo #define GREEN 3)

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. [22]

ANSI C y ISO C

A finales de la década de 1970 y durante la de 1980, se implementaron versiones de C para una amplia variedad de computadoras mainframe , minicomputadoras y microcomputadoras , incluida la IBM PC , a medida que su popularidad comenzó a aumentar significativamente.

En 1983, el Instituto Nacional Estadounidense de Estándares (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 C de Unix 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 , Estándar C o, a veces, C89.

En 1990, la Organización Internacional de Normalización (ISO) adoptó la norma 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 de normalización nacionales, ya no desarrolla la norma C de forma independiente, sino que se remite a la norma C internacional, mantenida por el grupo de trabajo ISO/IEC JTC1/SC22 /WG14. La adopción nacional de una actualización de la norma internacional suele producirse en el plazo de un año a partir de la publicación de la ISO.

Uno de los objetivos del proceso de estandarización de C era producir un superconjunto de K&R C, que incorporara 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, compatibilidad con conjuntos de caracteres y configuraciones regionales internacionales y mejoras del preprocesador. Aunque se amplió la sintaxis para las declaraciones de parámetros para incluir el estilo utilizado en C++, se siguió permitiendo la interfaz K&R, por compatibilidad con el código fuente existente.

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

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

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 amplio para conjuntos de caracteres internacionales. [23]

C99

La norma C fue revisada nuevamente a fines de la década de 1990, lo que llevó a la publicación de la norma ISO/IEC 9899:1999 en 1999, conocida comúnmente como " C99 ". Desde entonces ha sido modificada tres veces mediante Corrigenda Técnicas. [24]

C99 introdujo varias características nuevas, incluidas funciones en línea , varios tipos de datos nuevos (incluidos long long inty un complextipo para representar números complejos ), matrices de longitud variable y miembros de matriz flexibles , compatibilidad mejorada con el punto flotante IEEE 754 , compatibilidad con macros variádicas (macros de aridad variable ) y compatibilidad con comentarios de una línea que comienzan con //, como en BCPL o C++. Muchas de estas ya se habían implementado como extensiones en varios compiladores de C.

C99 es en su mayor parte compatible con versiones anteriores de C90, pero es más estricto en algunos aspectos; en particular, una declaración que carece de un especificador de tipo ya no tiene intun valor implícito. __STDC_VERSION__Se define una macro estándar con un valor 199901Lpara indicar que está disponible el soporte de C99. GCC , Solaris Studio y otros compiladores de C ahora [ ¿cuándo? ] admiten muchas o todas las nuevas características de C99. Sin embargo, el compilador de C en Microsoft Visual C++ implementa el estándar C89 y aquellas partes de C99 que se requieren para la compatibilidad con C++11 . [25] [ necesita actualización ]

Además, el estándar C99 requiere soporte para identificadores que utilicen Unicode en forma de caracteres de escape (por ejemplo, \u0040o \U0001f431) y sugiere soporte para nombres Unicode sin formato.

C11

En 2007 se comenzó a trabajar en otra revisión del estándar C, denominada informalmente "C1X" hasta su publicación oficial, ISO/IEC 9899:2011, el 8 de diciembre de 2011. El comité de estándares C adoptó directrices para limitar la adopción de nuevas características que no habían sido probadas por implementaciones existentes.

El estándar C11 añade numerosas características nuevas a C y a la biblioteca, entre las que se incluyen macros genéricas de tipos, estructuras anónimas, compatibilidad mejorada con Unicode, operaciones atómicas, subprocesamiento múltiple y funciones con comprobación 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 para 201112Lindicar que se encuentra disponible la compatibilidad con C11.

C17

C17 es un nombre informal para la norma ISO/IEC 9899:2018, un estándar para el lenguaje de programación C publicado en junio de 2018. No introduce nuevas características del lenguaje, solo correcciones técnicas y aclaraciones sobre defectos en C11. La macro estándar __STDC_VERSION__se define para 201710Lindicar que se encuentra disponible el soporte para C17.

C23

C23 es un nombre informal para la revisión estándar actual del lenguaje C. Se lo conocía informalmente como "C2X" durante la mayor parte de su desarrollo. C23 se publicó en octubre de 2024 como ISO/IEC 9899:2024. [26] La macro estándar __STDC_VERSION__se define para 202311Lindicar que se encuentra disponible la compatibilidad con C23.

C2Y

C2Y es un nombre informal para la próxima revisión importante del estándar del lenguaje C, después de C23 (C2X), que se espera que se publique más adelante en la década de 2020, de ahí el '2' en "C2Y". Un borrador preliminar de trabajo de C2Y fue publicado en febrero de 2024 como N3220 por el grupo de trabajo ISO/IEC JTC1/SC22 /WG14. [27]

C incrustado

Históricamente, la programación C integrada requiere extensiones no estándar del lenguaje C para soportar 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 ampliaba el lenguaje C [28] para abordar estos problemas al proporcionar un estándar común al que debían adherirse todas las implementaciones. Incluye una serie de características que no están disponibles en el lenguaje C normal, como la aritmética de punto fijo, los espacios de direcciones con nombre y el direccionamiento básico de hardware de E/S.

Sintaxis

C tiene una gramática formal especificada por el estándar C. [29] Los finales de línea generalmente no son significativos en C; sin embargo, los límites de línea sí 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 se anidan, y estas secuencias de caracteres no se interpretan como delimitadores de comentarios si aparecen dentro de literales de cadena o de caracteres. [30]

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

Como lenguaje imperativo, C utiliza sentencias para especificar acciones. La sentencia más común es una sentencia de expresión , que consiste en una expresión a evaluar, seguida de un punto y coma; como efecto secundario de la evaluación, se pueden llamar funciones y asignar nuevos valores a las variables. Para modificar la ejecución secuencial normal de sentencias, C proporciona varias sentencias de flujo de control identificadas por palabras clave reservadas. La programación estructurada está respaldada por if... [ else] ejecución condicional y por do... while, while, y forejecución iterativa (bucle). La forsentencia tiene expresiones de inicialización, prueba y reinicialización independientes, cualquiera o todas las cuales se pueden omitir. breaky continuese puede utilizar dentro del bucle. Break se utiliza para salir de la sentencia de bucle que encierra más internamente y continue se utiliza para saltar a su reinicialización. También hay una gotosentencia no estructurada que se ramifica directamente a la etiqueta designada dentro de la función. switchselecciona una casepara ser ejecutada en función del valor de una expresión entera. A diferencia de muchos otros lenguajes, el flujo de control pasará al siguiente casea menos que finalice con un break.

Las expresiones pueden utilizar 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 en variables) se producirá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 a función. Los puntos de secuencia también se producen durante la evaluación de 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". [31] El estándar C no intentó corregir muchos de estos defectos, debido al impacto de dichos cambios en el software ya existente.

Conjunto de caracteres

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

El carácter de nueva línea indica el final de una línea de texto; no necesita corresponder a un único carácter real, aunque por conveniencia C lo trata como tal.

Se pueden utilizar caracteres codificados multibyte adicionales en literales de cadena , pero no son completamente portables . El último estándar de C ( C11 ) permite que caracteres Unicode multinacionales se incorporen de manera portable dentro del texto fuente de C mediante el uso de codificación \uXXXXo \UXXXXXXXX(donde Xdenota un carácter hexadecimal), aunque esta característica aún no está ampliamente implementada. [ necesita actualización ]

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 . La compatibilidad en tiempo de ejecución con conjuntos de caracteres extendidos ha aumentado con cada revisión del estándar C.

Palabras reservadas

Las siguientes palabras reservadas distinguen entre mayúsculas y minúsculas .

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

C99 agregó cinco palabras reservadas más: (‡ indica un alias de ortografía alternativo para una palabra clave C23)

C11 agregó siete palabras reservadas más: [32] (‡ indica un alias de ortografía alternativo para una palabra clave C23)

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

C23 reservó quince palabras más:

  • alignas
  • alignof
  • bool
  • constexpr
  • false
  • nullptr
  • static_assert
  • thread_local
  • true
  • typeof
  • typeof_unqual
  • _BitInt
  • _Decimal32
  • _Decimal64
  • _Decimal128

La mayoría de las palabras recientemente reservadas 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 exclusivo en implementaciones. Dado que el código fuente de los programas existentes no debería haber estado utilizando 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 los identificadores con guión bajo. Algunas de esas palabras se agregaron como palabras clave con su ortografía convencional en C23 y se eliminaron las macros correspondientes.

Antes de C89, entryestaba reservada como palabra clave. En la segunda edición de su libro The C Programming Language , que describe lo que se conocería como C89, Kernighan y Ritchie escribieron: "La ... [palabra clave] entry, anteriormente reservada pero nunca utilizada, ya no está reservada" y "La entrypalabra clave que nació muerta se retira". [33]

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 deben realizar al evaluar esa expresión. C tiene operadores para:

C utiliza 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 utiliza el operador ==para probar la igualdad. La similitud entre los operadores de asignación e igualdad puede dar como resultado 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 por error como if (a = b + 1), que se evaluará como truea menos que el valor de asea 0posterior a la asignación. [34]

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

Ejemplo de "Hola, mundo"

Programa "¡Hola, mundo!" de Brian Kernighan (1978)

El ejemplo "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 una terminal o una pantalla.

La versión original fue: [36]

main () { printf ( "hola, mundo \n " ); } 

Un programa "hola, mundo" que cumple con el estándar es: [a]

#incluir <stdio.h> int main ( void ) { printf ( "hola, mundo \n " ); }  

La primera línea del programa contiene una directiva de preprocesamiento , indicada por #include. Esto hace que el compilador reemplace esa línea de código con el texto completo del stdio.harchivo de encabezado, que contiene declaraciones para funciones de entrada y salida estándar como printfy scanf. Los corchetes angulares que lo rodean stdio.hindican que el archivo de encabezado se puede ubicar utilizando una estrategia de búsqueda que prefiere los encabezados proporcionados con el compilador a otros encabezados que tienen el mismo nombre (a diferencia de las comillas dobles que generalmente incluyen archivos de encabezado locales o específicos del proyecto).

mainLa segunda línea indica que se está definiendo una función denominada . La mainfunción cumple una función especial en los programas C; el entorno de ejecución llama a la mainfunción para comenzar la ejecución del programa. El especificador de tipo intindica que el valor devuelto al invocador (en este caso, el entorno de ejecución) como resultado de la evaluación de la mainfunción es un entero. La palabra clave voidcomo lista de parámetros indica que la mainfunción no acepta argumentos. [b]

La llave de apertura indica el comienzo del código que define la mainfunción.

La siguiente línea del programa es una sentencia que llama (es decir, desvía la ejecución a) una función denominada printf, que en este caso se suministra desde una biblioteca del sistema . En esta llamada, se pasa aprintf la función (es decir, se le proporciona) un único argumento, que es la dirección del primer carácter en el literal de cadena . El literal de cadena es una matriz sin nombre configurada automáticamente por el compilador, con elementos de tipo y un carácter NULL final (valor ASCII 0) que marca el final de la matriz (para permitir determinar la longitud de la cadena). El carácter NULL también se puede escribir como la secuencia de escape . La es una secuencia de escape estándar que C traduce a un carácter de nueva línea , que, en la salida, significa el final de la línea actual. El valor de retorno de la función es de tipo , pero se descarta silenciosamente ya que no se usa. (Un programa más cuidadoso podría probar el valor de retorno para verificar que la función tuvo éxito). El punto y coma termina la sentencia. "hello, world\n"charprintf \0\nprintfintprintf;

La llave de cierre indica el final del código de la mainfunción. Según la especificación C99 y posteriores, la mainfunción (a diferencia de cualquier otra función) devolverá implícitamente un valor de 0al alcanzar el }que finaliza la función. [c] El valor de retorno de 0es interpretado por el sistema de tiempo de ejecución como un código de salida que indica la ejecución exitosa de la función. [37]

Tipos de datos

El sistema de tipos en C es estático y débilmente tipado , lo que lo hace similar al sistema de tipos de los descendientes de ALGOL como Pascal . [38] 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).

El lenguaje C se utiliza a menudo en la programación de sistemas de bajo nivel en la que pueden ser necesarios escapes 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 maneras, ya sea mediante una conversión de tipos para convertir explícitamente un valor de un tipo a otro, o mediante punteros o uniones para reinterpretar los bits subyacentes de un objeto de datos de alguna otra manera.

Algunos consideran que la sintaxis de declaración de C no es intuitiva, en particular para los punteros de función . (La idea de Ritchie era declarar identificadores en contextos que se asemejaran a su uso: " la declaración refleja el uso ".) [39]

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 números 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 a la que apuntan o para invocar una función a la que apuntan. 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 normalmente una dirección de memoria sin formato (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 a la que apuntan, las expresiones que incluyen punteros se pueden comprobar en tiempo de compilación. La aritmética de punteros se escala automáticamente según el tamaño del tipo de datos al que apuntan.

Los punteros se utilizan para muchos propósitos en C. Las cadenas de texto se manipulan comúnmente utilizando punteros en matrices de caracteres. La asignación de memoria dinámica se realiza utilizando punteros; el resultado de a mallocgeneralmente se convierte al tipo de datos de los datos que se almacenarán. Muchos tipos de datos, como árboles , se implementan comúnmente como structobjetos asignados dinámicamente vinculados entre sí mediante punteros. Los punteros a otros punteros se utilizan a menudo en matrices multidimensionales y matrices de structobjetos. Los punteros a funciones ( punteros de función ) son útiles para pasar funciones como argumentos a funciones de orden superior (como qsort o bsearch ), en tablas de despacho o como devoluciones de llamadas a controladores de eventos . [37]

Un valor de puntero nulo apunta explícitamente a una ubicación no válida. La desreferenciación de un valor de puntero nulo no está definida, lo que a menudo da como resultado un error de segmentación . Los valores de puntero nulo son útiles para indicar casos especiales, como la ausencia de un puntero "próximo" en el nodo final de una lista enlazada , 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, como la NULLmacro definida por varios encabezados estándar o, desde C23, con la constante nullptr. En contextos condicionales, los valores de puntero nulo evalúan como false, mientras que todos los demás valores de puntero evalúan como true.

Los punteros void ( void *) apuntan a objetos de un tipo no especificado y, por lo tanto, pueden utilizarse como punteros de datos "genéricos". Dado que no se conoce el tamaño ni el tipo del objeto al que apuntan, no se puede desreferenciar a los punteros void ni se permite la aritmética de punteros sobre ellos, aunque se pueden convertir fácilmente (y en muchos contextos se convierten de manera implícita) a y desde cualquier otro tipo de puntero de objeto. [37]

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

Matrices

Los tipos de matrices en C son tradicionalmente de un tamaño fijo y estático que se especifica en tiempo de 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 una matriz.

Dado que siempre se accede a las matrices (en efecto) a través de punteros, los accesos a las matrices normalmente no se verifican con el tamaño de la matriz subyacente, aunque algunos compiladores pueden proporcionar la verificación de límites como una opción. [40] [41] Por lo tanto, las violaciones de los límites de la matriz son posibles y pueden llevar a varias repercusiones, incluidos accesos ilegales a la memoria, corrupción de datos, desbordamientos de búfer y excepciones en tiempo de ejecución.

C no tiene una disposición especial para declarar matrices multidimensionales , sino que se basa en la recursión dentro del sistema de tipos para declarar matrices de matrices, lo que efectivamente logra lo mismo. Los valores de índice de la "matriz multidimensional" resultante se pueden considerar como crecientes 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 de C es muy adecuada para esta tarea en particular. Sin embargo, en las primeras versiones de C, los límites de la matriz deben ser valores fijos conocidos o, de lo contrario, pasarse explícitamente a cualquier subrutina que los requiera, y no se puede acceder a matrices de matrices de tamaño dinámico mediante indexación doble. (Una solución alternativa para esto fue asignar la matriz con un "vector de fila" adicional de punteros a las columnas). C99 introdujo "matrices de longitud variable" que solucionan este problema.

El siguiente ejemplo que utiliza C moderno (C99 o posterior) muestra la asignación de una matriz bidimensional en el montón y el uso de indexación de matriz multidimensional para accesos (que pueden usar verificación de límites en muchos compiladores de C):

int func ( int N , int M ) { float ( * p )[ N ] [ M ] = malloc ( sizeof * p ); if ( p == 0 ) return -1 ; for ( int i = 0 ; i < N ; i ++ ) for ( int j = 0 ; j < M ; j ++ ) ( * p )[ i ] [ j ] = i + j ; print_array ( N , M , p ); free ( p ); return 1 ; }                                              

Y aquí hay una implementación similar que utiliza la función Auto VLA de C99 : [d]

int func ( int N , int M ) { // Precaución: se deben realizar comprobaciones para garantizar que N*M*sizeof(float) NO exceda las limitaciones para los VLA automáticos y esté dentro del tamaño disponible de la pila. float p [ N ] [ M ]; // el VLA automático se mantiene en la pila y se dimensiona cuando se invoca la función for ( int i = 0 ; i < N ; i ++ ) for ( int j = 0 ; j < M ; j ++ ) p [ i ] [ j ] = i + j ; print_array ( N , M , p ); // no es necesario free(p) ya que desaparecerá cuando la función salga, junto con el resto del marco de la pila return 1 ; }                                       

Intercambiabilidad de matrices y punteros

La notación de subíndice x[i](donde xdesigna un puntero) es una sintaxis simplificada para *(x+i). [42] Aprovechando el conocimiento del compilador sobre el tipo de puntero, la dirección a la que x + iapunta no es la dirección base (a la que apunta x) incrementada en ibytes, sino que se define como la dirección base incrementada por imultiplicada por el tamaño de un elemento xal que apunta. Por lo tanto, x[i]designa el i+1elemento n de la matriz.

Además, en la mayoría de los contextos de expresión (una excepción notable es como operando de sizeof), una expresión de tipo 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 la nombra como 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 en realidad por referencia .

El tamaño total de una matriz xse puede determinar aplicando sizeofa una expresión de tipo matriz. El tamaño de un elemento se puede determinar aplicando el operador sizeofa cualquier elemento desreferenciado de una matriz A, como en n = sizeof A[0]. Por lo tanto, la cantidad de elementos en una matriz declarada Ase puede determinar como sizeof A / sizeof A[0]. Tenga en cuenta que si solo está disponible un puntero al primer elemento, como suele ser el caso en el código C debido a la conversión automática descrita anteriormente, se pierde la información sobre el tipo completo de la matriz y su longitud.

Gestión de la memoria

Una de las funciones más importantes de un lenguaje de programación es proporcionar facilidades para gestionar la memoria y los objetos que se almacenan en ella. C ofrece tres formas principales de asignar memoria a los objetos: [37]

  • Asignación de memoria estática : se proporciona espacio para el objeto en el binario en tiempo de compilación; estos objetos tienen una extensión (o vida útil) mientras el binario que los contiene esté cargado en la memoria.
  • Asignación automática de memoria : los objetos temporales se pueden almacenar en la pila , y este espacio se libera y se puede reutilizar automáticamente después de salir del bloque en el que están declarados.
  • Asignación de memoria dinámica : se pueden solicitar bloques de memoria de tamaño arbitrario en tiempo de ejecución utilizando funciones de biblioteca, como mallocdesde una región de memoria llamada montón ; estos bloques persisten hasta que se liberan posteriormente para su reutilización llamando a la función de biblioteca realloco free.

Estos tres enfoques son apropiados en diferentes situaciones y tienen varias ventajas y desventajas. 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 cantidad de 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 entre las llamadas de función, la asignación automática es fácil de usar pero el espacio de pila es típicamente mucho más limitado y transitorio que la memoria estática o el espacio de montón, y la asignación de memoria dinámica permite la asignación conveniente de objetos cuyo tamaño se conoce solo en tiempo de ejecución. La mayoría de los programas C hacen un uso extensivo de los tres.

Siempre que sea posible, la asignación automática o estática suele ser la más sencilla, ya que el compilador gestiona el almacenamiento, 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 la asignación dinámica es necesaria. [37] Antes del estándar C99, las matrices de tamaño variable eran un ejemplo común de esto. (Consulte el artículo sobre la asignación dinámica de memoria en C para 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 incontroladas, las funciones de asignación dinámica devuelven una indicación (en forma de un valor de puntero nulo) cuando no se puede asignar el almacenamiento requerido. (La asignación estática que es demasiado grande suele ser detectada por el enlazador 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 nulos o cero al iniciar el programa. Los objetos asignados de forma automática y dinámica 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 podría no representar ni siquiera 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 estar sincronizada 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 queda fuera de 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 para el programa, un fenómeno conocido como pérdida de memoria . Por el contrario, es posible que se libere memoria, pero que se haga referencia a ella posteriormente, lo que lleva a resultados impredecibles. Normalmente, los síntomas de error aparecen en una parte del programa no relacionada con el código que causa el error, lo que dificulta el diagnóstico del error. Estos problemas se mejoran en lenguajes con recolección automática de basura .

Bibliotecas

El lenguaje de programación C utiliza bibliotecas como su principal método de extensión. En C, una biblioteca es un conjunto de funciones contenidas en un único archivo "archivado". Cada biblioteca normalmente tiene un archivo de encabezado , que contiene los prototipos de las funciones contenidas en la biblioteca que pueden ser utilizadas por un programa, y ​​las declaraciones de tipos de datos especiales y símbolos de macro utilizados con estas funciones. Para que un programa utilice una biblioteca, debe incluir el archivo de encabezado de la biblioteca, y la biblioteca debe estar vinculada con el programa, lo que en muchos casos requiere indicadores del compilador (por ejemplo, -lm, abreviatura de "vincular la biblioteca matemática"). [37]

La biblioteca C más común es la biblioteca estándar C , que está especificada por los estándares C ISO y ANSI y viene con cada implementación C (las implementaciones que apuntan a entornos limitados, como 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 estas y otras funciones de la biblioteca estándar.

Otro conjunto común de funciones de la biblioteca C son las que utilizan las aplicaciones específicamente diseñadas para sistemas Unix y similares , especialmente las funciones que proporcionan una interfaz al núcleo . 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 suelen escribirse en C porque los compiladores de C generan código objeto eficiente ; luego, los programadores crean interfaces con la biblioteca para que las rutinas se puedan usar desde lenguajes de nivel superior como Java , Perl y Python . [37]

Manejo de archivos y transmisiones

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 . Un flujo es desde esta perspectiva 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 a través de la asociación de un flujo a un archivo. En la biblioteca estándar de C, se utiliza temporalmente un búfer (un área de memoria o cola) para almacenar datos antes de que se envíen al destino final. Esto reduce el tiempo de espera de 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 son parte de la biblioteca estándar de C [ aclaración necesaria ] pero generalmente son parte de la programación "bare metal" (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 sentencias con un comportamiento indefinido o expresiones posiblemente erróneas, con un rigor mayor que el proporcionado por el compilador. La herramienta lint fue la primera de ellas, y dio origen a muchas otras.

La verificación y auditoría automáticas del código fuente son beneficiosas en cualquier lenguaje, y para C existen muchas herramientas de este tipo, como Lint . Una práctica común es utilizar 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 es probable que en realidad sean errores. MISRA C es un conjunto propietario de pautas para evitar ese código cuestionable, desarrollado para sistemas integrados. [43]

También hay compiladores, bibliotecas y mecanismos a nivel de sistema operativo para realizar acciones que no son una parte estándar de C, como la comprobación de límites para matrices, la detección de desbordamiento de búfer , la serialización , el seguimiento dinámico de memoria y la 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. [44] [45]

Usos

Justificación de su uso en la programación de sistemas

Algunos programas escritos en C

C se utiliza ampliamente para la programación de sistemas en la implementación de sistemas operativos y aplicaciones de sistemas integrados . [46] Esto se debe a varias razones:

  • El lenguaje C permite acceder al hardware y a la memoria de la plataforma con punteros y juegos de palabras de tipos , de modo que las características específicas del sistema (por ejemplo, registros de control/estado , registros de E/S ) se pueden configurar y usar con código escrito en C; permite el control total de la plataforma en la que se ejecuta.
  • El código generado después de la compilación no exige muchas funciones del sistema y puede invocarse desde algún código de arranque de manera directa: es fácil de ejecutar.
  • Las declaraciones y expresiones del lenguaje C generalmente se asignan bien a secuencias de instrucciones para el procesador de destino y, en consecuencia, hay una baja demanda de tiempo de ejecución en los recursos del sistema: es rápido de ejecutar.
  • Con su amplio conjunto de operadores, el lenguaje C puede utilizar muchas de las características de las CPU de destino. Cuando una CPU en particular tiene instrucciones más esotéricas, se puede construir una variante del lenguaje con funciones quizás intrínsecas para explotar esas instrucciones; puede utilizar prácticamente todas las características de la CPU de destino.
  • El lenguaje facilita la superposición de estructuras sobre bloques de datos binarios, lo que permite comprender, navegar y modificar los datos; puede escribir estructuras de datos e incluso sistemas de archivos.
  • El lenguaje admite un amplio conjunto de operadores, incluida la manipulación de bits, para aritmética y lógica de números enteros y, tal vez, diferentes tamaños de números de punto flotante; puede procesar datos estructurados adecuadamente de manera eficaz.
  • C es un lenguaje bastante pequeño, con sólo unas pocas declaraciones y sin demasiadas características que generen un código de destino extenso: es comprensible.
  • C tiene control directo sobre la asignación y desasignación de memoria, lo que otorga una eficiencia razonable y tiempos predecibles a las operaciones de manejo de memoria, sin preocupaciones por eventos esporádicos de recolección de basura que detengan el mundo : tiene un rendimiento predecible.
  • C permite el uso y la implementación de diferentes esquemas de asignación de memoria , incluyendo uno típico malloc; freeun mecanismo más sofisticado con arenas ; o una versión para un núcleo de sistema operativo que puede adaptarse a DMA , usarse dentro de controladores de interrupciones o integrarse con el sistema de memoria virtual .
  • Dependiendo del enlazador y del entorno, el código C también puede llamar a bibliotecas escritas en lenguaje ensamblador , y puede ser llamado desde el lenguaje ensamblador – interopera bien con otro código de nivel inferior.
  • C y sus convenciones de llamada y estructuras de enlace se usan comúnmente junto con otros lenguajes de alto nivel, con soporte para llamadas tanto a C como desde C: interopera bien con otro código de alto nivel.
  • C tiene un ecosistema muy maduro y amplio, que incluye bibliotecas, marcos, compiladores de código abierto, depuradores y utilidades, y es el estándar de facto. Es probable que los controladores ya existan en C, o que exista una arquitectura de CPU similar como back-end de un compilador de C, por lo que hay menos incentivos para elegir otro lenguaje.

Se utiliza para bibliotecas con uso intensivo de recursos computacionales.

C permite a los programadores crear implementaciones eficientes de algoritmos y estructuras de datos, porque la capa de abstracción del hardware es delgada y su sobrecarga es baja, un criterio importante para programas de gran intensidad computacional. Por ejemplo, la Biblioteca de aritmética de precisión múltiple de GNU , la Biblioteca científica de GNU , Mathematica y MATLAB están escritas total o parcialmente en C. Muchos lenguajes admiten la llamada a funciones de biblioteca en C; por ejemplo, el marco de trabajo NumPy basado en Python utiliza C para los aspectos de alto rendimiento e interacción con hardware.

C como lenguaje intermedio

En ocasiones, C se utiliza como lenguaje intermedio en las implementaciones de otros lenguajes. Este enfoque se puede utilizar por razones 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-- . Además, los principales compiladores contemporáneos GCC y LLVM cuentan con una representación intermedia que no es C, y esos compiladores admiten interfaces para muchos lenguajes, incluido C.

Otros lenguajes escritos en C

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. [47] Por ejemplo, las implementaciones de referencia de Python , [48] Perl , [49] Ruby , [50] y PHP [51] están escritas en C.

Una vez utilizado para el desarrollo web

Históricamente, C se ha utilizado a veces para el desarrollo web utilizando la Interfaz de Puerta de Enlace Común (CGI) como una "puerta de enlace" para la información entre la aplicación web, el servidor y el navegador. [52] C puede haber sido elegido en lugar de los lenguajes interpretados debido a su velocidad, estabilidad y disponibilidad casi universal. [53] Ya no es una práctica común que el desarrollo web se realice en C, [54] y existen muchas otras herramientas de desarrollo web .

Servidores web

Los dos servidores web más populares , Apache HTTP Server y Nginx , están escritos en C. Estos servidores web interactúan con el sistema operativo, escuchan en los puertos TCP las solicitudes HTTP y luego ofrecen contenido web estático o provocan la ejecución de otros lenguajes que manejan el contenido como PHP , que está escrito principalmente en C. El enfoque cercano al metal de C permite la construcción de estos sistemas de software de alto rendimiento.

Aplicaciones para el usuario final

C también se ha utilizado ampliamente para implementar aplicaciones para el usuario final . [55] Sin embargo, dichas aplicaciones también pueden escribirse en lenguajes más nuevos y de nivel superior.

Limitaciones

El poder del lenguaje ensamblador y la conveniencia del lenguaje ensamblador

—Dennis  Ritchie [56]

Si bien el lenguaje C ha sido popular, influyente y enormemente exitoso, tiene desventajas, entre ellas:

  • El manejo de memoria dinámica estándar con mallocy freees propenso a errores. Entre los errores se incluyen: pérdidas de memoria cuando se asigna memoria pero no se libera y acceso a memoria previamente liberada.
  • El uso de punteros y la manipulación directa de la memoria significa que la corrupción de la memoria es posible, quizás debido a un error del programador o a una verificación insuficiente de datos erróneos.
  • Existe cierta verificación de tipos , pero no se aplica a áreas como las funciones variádicas , y la verificación de tipos se puede eludir de manera trivial o inadvertida. Está tipada débilmente .
  • Dado que el código generado por el compilador contiene pocas comprobaciones, el programador tiene la carga de considerar todos los resultados posibles, protegerse contra desbordamientos de búfer, comprobación de límites de matriz, desbordamientos de pila , agotamiento de memoria y considerar condiciones de carrera , aislamiento de subprocesos, etc.
  • El uso de punteros y su manipulación en tiempo de ejecución implica que puede haber dos formas de acceder a los mismos datos (aliasing), lo que no se puede determinar en tiempo de compilación. Esto significa que algunas optimizaciones que pueden estar disponibles para otros lenguajes no son posibles en C. Se considera que FORTRAN es más rápido.
  • Algunas de las funciones de la biblioteca estándar, por ejemplo scanfo strncat, pueden provocar desbordamientos de búfer .
  • Existe una estandarización limitada en el soporte para variantes de bajo nivel en el código generado, por ejemplo: diferentes convenciones de llamada de función y ABI ; diferentes convenciones de empaquetado de estructura ; diferente orden de bytes dentro de números enteros más grandes (incluyendo endianness). En muchas implementaciones de lenguaje, algunas de estas opciones pueden manejarse con la directiva preprocessor #pragma, [57] [58] y algunas con palabras clave adicionales, por ejemplo use __cdeclcalling Convention. Pero la directiva y las opciones no son compatibles de manera consistente. [59]
  • El manejo de cadenas mediante la biblioteca estándar requiere un uso intensivo de código y una gestión explícita de la memoria.
  • El lenguaje no admite directamente la orientación a objetos, la introspección , la evaluación de expresiones en tiempo de ejecución, los genéricos, etc.
  • Existen pocas protecciones contra el uso inapropiado de las características del lenguaje, que pueden llevar a un código inmantenible . En particular, el preprocesador de C puede ocultar efectos problemáticos como la doble evaluación y cosas peores. [60] Esta facilidad para el código complicado se ha celebrado con competiciones como el Concurso Internacional de Código C Ofuscado y el Concurso de C Underhanded .
  • C carece de soporte estándar para el manejo de excepciones y solo ofrece códigos de retorno para la comprobación de errores. Las funciones de la biblioteca estándar setjmpylongjmp se han utilizado [61] para implementar un mecanismo try-catch mediante macros.

Para algunos propósitos, se han adoptado estilos restringidos de C, por ejemplo, MISRA C o CERT C , en un intento de reducir la posibilidad de errores. Las bases de datos como CWE intentan contar las formas en que C, etc., tiene vulnerabilidades, junto con recomendaciones para mitigarlas.

Existen herramientas que pueden mitigar algunos de los inconvenientes. Los compiladores de C actuales incluyen comprobaciones que pueden generar advertencias para ayudar a identificar muchos errores potenciales.

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

C ha influido tanto directa como indirectamente en muchos lenguajes posteriores como C++ y Java . [63] La influencia más generalizada ha sido sintáctica; todos los lenguajes mencionados combinan la sintaxis de declaración y expresión (más o menos reconocible) de C con sistemas de tipos, modelos de datos o estructuras de programas a gran escala que difieren de los de C, a veces radicalmente.

Existen varios intérpretes de C o similares, incluidos Ch y CINT , que también se pueden utilizar para crear scripts.

Cuando los lenguajes de programación 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 código fuente a código fuente ; el código fuente se traducía a C y luego se compilaba con un compilador de C. [64]

El lenguaje de programación C++ (originalmente llamado "C con clases ") fue ideado por Bjarne Stroustrup como un enfoque para proporcionar funcionalidad orientada a objetos con una sintaxis similar a C. [65] C++ agrega mayor fuerza de tipado, 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 [ ¿cuándo? ] admite la mayor parte de C, con unas pocas excepciones .

Objective-C era originalmente una capa muy "delgada" sobre 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 para 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.

Véase también

Notas

  1. ^ El código de ejemplo original se compilará en la mayoría de los compiladores modernos que no se encuentran en modo de cumplimiento estricto de estándares, pero no cumple totalmente con los requisitos de C89 ni de C99. De hecho, C99 requiere que se produzca un mensaje de diagnóstico.
  2. ^ La mainfunción tiene dos argumentos, int argcy char *argv[], respectivamente, que se pueden usar para manejar argumentos de línea de comandos . El estándar ISO C (sección 5.1.2.2.1) requiere mainque se admitan ambas formas de , lo que es un tratamiento especial que no se brinda a ninguna otra función.
  3. ^ Antes de C99, return 0;se requería una declaración explícita al final de la mainfunción.
  4. ^ El código de print_array(no se muestra) difiere ligeramente, [ ¿por qué? ] también.

Referencias

  1. ^ ab Prinz, Peter; Crawford, Tony (16 de diciembre de 2005). C en pocas palabras. O'Reilly Media, Inc. pág. 3. ISBN 9780596550714.
  2. ^ Ritchie (1993): "Thompson había hecho un breve intento de producir un sistema codificado en una versión temprana de C —antes de las estructuras— en 1972, pero abandonó el esfuerzo".
  3. ^ "N3221 - Informe del editor, reunión posterior a enero de 2024 en Estrasburgo, Francia". ISO/IEC JTC1/SC22/WG14 . Estándares abiertos. 21 de febrero de 2024 . Consultado el 24 de mayo de 2024 .
  4. ^ Ritchie (1993): "El esquema de composición de tipos adoptado por C debe mucho a Algol 68, aunque tal vez no surgió en una forma que los seguidores de Algol aprobarían".
  5. ^ ab "Verilog HDL (y C)" (PDF) . The Research School of Computer Science at the Australian National University. 3 de junio de 2010. Archivado desde el original (PDF) el 6 de noviembre de 2013 . Consultado el 19 de agosto de 2013 . Década de 1980: se presenta por primera vez Verilog; Verilog se inspira en el lenguaje de programación C
  6. ^ "El nombre se basa en la letra C del alfabeto inglés y se pronuncia como ella". el sonido del lenguaje de programación c . Diccionario inglés chino. Archivado desde el original el 17 de noviembre de 2022 . Consultado el 17 de noviembre de 2022 .
  7. ^ Munoz, Daniel. "Después de todos estos años, el mundo todavía funciona con programación en C | Toptal". Blog de ingeniería de Toptal . Consultado el 15 de junio de 2024 .
  8. ^ "El lenguaje C cae al nivel de popularidad más bajo". Developer.com . 9 de agosto de 2016. Archivado desde el original el 22 de agosto de 2022 . Consultado el 1 de agosto de 2022 .
  9. ^ abcdef Ritchie (1993)
  10. ^ "Popularidad de los lenguajes de programación". 2009. Archivado desde el original el 16 de enero de 2009. Consultado el 16 de enero de 2009 .
  11. ^ "Índice de la comunidad de programación TIOBE". 2009. Archivado desde el original el 4 de mayo de 2009. Consultado el 6 de mayo de 2009 .
  12. ^ Ward, Terry A. (agosto de 1983). "Bibliografía C/A anotada del lenguaje C". Byte . pág. 268. Consultado el 31 de enero de 2015 .
  13. ^ "Índice TIOBE de septiembre de 2024". Archivado desde el original el 18 de septiembre de 2024 . Consultado el 20 de septiembre de 2024 .
  14. ^ Ritchie, Dennis. «BCPL to B to C» (De BCPL a B a C). lysator.liu.se . Archivado desde el original el 12 de diciembre de 2019. Consultado el 10 de septiembre de 2019 .
  15. ^ abcde Jensen, Richard (9 de diciembre de 2020). ""Una cosa malditamente estúpida"—los orígenes de C". Ars Technica . Archivado desde el original el 28 de marzo de 2022 . Consultado el 28 de marzo de 2022 .
  16. ^ ab Johnson, SC ; Ritchie, DM (1978). "Portabilidad de programas C y el sistema UNIX". Bell System Tech. J . 57 (6): 2021–2048. CiteSeerX 10.1.1.138.35 . doi :10.1002/j.1538-7305.1978.tb02141.x. ISSN  0005-8580. S2CID  17510065. (Nota: El PDF es un escaneo OCR del original y contiene una representación de "IBM 370" como "IBM 310").
  17. ^ McIlroy, MD (1987). A Research Unix reader: annotated excerpts from the Programmer's Manual, 1971–1986 (PDF) (Informe técnico). CSTR. Bell Labs. pág. 10. 139. Archivado (PDF) del original el 11 de noviembre de 2017. Consultado el 1 de febrero de 2015 .
  18. ^ Kernighan, Brian W. ; Ritchie, Dennis M. (febrero de 1978). El lenguaje de programación C (1.ª ed.). Englewood Cliffs, NJ : Prentice Hall . ISBN 978-0-13-110163-0.
  19. ^ "Páginas del manual de C". Manual de información miscelánea de FreeBSD (FreeBSD 13.0 ed.). 30 de mayo de 2011. Archivado desde el original el 21 de enero de 2021 . Consultado el 15 de enero de 2021 .[1] Archivado el 21 de enero de 2021 en Wayback Machine.
  20. ^ Kernighan, Brian W. ; Ritchie, Dennis M. (marzo de 1988). El lenguaje de programación C (2.ª ed.). Englewood Cliffs, NJ : Prentice Hall . ISBN 978-0-13-110362-7.
  21. ^ Stroustrup, Bjarne (2002). Rivalidad entre hermanos: C y C++ (PDF) (Informe). AT&T Labs. Archivado (PDF) del original el 24 de agosto de 2014. Consultado el 14 de abril de 2014 .
  22. ^ "Fundamento de la Norma Nacional Estadounidense para Sistemas de Información – Lenguaje de Programación – C". Archivado desde el original el 17 de julio de 2024 . Consultado el 17 de julio de 2024 .
  23. ^ C Integridad. Organización Internacional de Normalización. 30 de marzo de 1995. Archivado desde el original el 25 de julio de 2018 . Consultado el 24 de julio de 2018 .
  24. ^ "JTC1/SC22/WG14 – C". Página de inicio . ISO/IEC. Archivado desde el original el 12 de febrero de 2018 . Consultado el 2 de junio de 2011 .
  25. ^ Andrew Binstock (12 de octubre de 2011). «Entrevista con Herb Sutter». Dr. Dobbs . Archivado desde el original el 2 de agosto de 2013. Consultado el 7 de septiembre de 2013 .
  26. ^ "WG14-N3132: Programa revisado de C23" (PDF) . open-std.org . 4 de junio de 2023. Archivado (PDF) del original el 9 de junio de 2023.
  27. ^ "WG14-N3220: Borrador de trabajo, C2y" (PDF) . open-std.org . 21 de febrero de 2024. Archivado (PDF) del original el 26 de febrero de 2024.
  28. ^ "TR 18037: Embedded C" (PDF) . open-std.org . 4 de abril de 2006. ISO/IEC JTC1 SC22 WG14 N1169. Archivado (PDF) del original el 25 de febrero de 2021 . Consultado el 26 de julio de 2011 .
  29. ^ Harbison, Samuel P.; Steele, Guy L. (2002). C: A Reference Manual (quinta edición). Englewood Cliffs, Nueva Jersey : Prentice Hall . ISBN 978-0-13-089592-9.Contiene una gramática BNF para C.
  30. ^ Kernighan y Ritchie (1988), pág. 192.
  31. ^ Kernighan y Ritchie (1978), pág. 3.
  32. ^ "Borrador del Comité ISO/IEC 9899:201x (ISO C11)" (PDF) . open-std.org . 2 de diciembre de 2010. Archivado (PDF) desde el original el 22 de diciembre de 2017 . Consultado el 16 de septiembre de 2011 .
  33. ^ Kernighan y Ritchie (1988), págs.192, 259.
  34. ^ "10 errores comunes de programación en C++". Cs.ucr.edu . Archivado desde el original el 21 de octubre de 2008 . Consultado el 26 de junio de 2009 .
  35. ^ Schultz, Thomas (2004). C y el 8051 (3.ª ed.). Otsego, MI: PageFree Publishing Inc. pág. 20. ISBN 978-1-58961-237-2. Recuperado el 10 de febrero de 2012 .
  36. ^ Kernighan y Ritchie (1978), pág. 6.
  37. ^ abcdefg Klemens, Ben (2013). Siglo XXI C. Medios O'Reilly . ISBN 978-1-4493-2714-9.
  38. ^ Feuer, Alan R.; Gehani, Narain H. (marzo de 1982). "Comparación de los lenguajes de programación C y Pascal". ACM Computing Surveys . 14 (1): 73–92. doi :10.1145/356869.356872. S2CID  3136859.
  39. ^ Kernighan y Ritchie (1988), pág. 122.
  40. ^ Por ejemplo, gcc proporciona _FORTIFY_SOURCE. "Características de seguridad: comprobaciones del búfer en tiempo de compilación (FORTIFY_SOURCE)". fedoraproject.org. Archivado desde el original el 7 de enero de 2007. Consultado el 5 de agosto de 2012 .
  41. ^ เอี่ยมสิริวงศ์, โอภาศ (2016). Programación con C. Bangkok, Tailandia: SE-EDUCATION PUBLIC COMPANY LIMITED. págs. 225-230. ISBN 978-616-08-2740-4.
  42. ^ Raymond, Eric S. (11 de octubre de 1996). The New Hacker's Dictionary (3.ª ed.). MIT Press. pág. 432. ISBN 978-0-262-68092-9. Recuperado el 5 de agosto de 2012 .
  43. ^ "Página de manual de lint (freebsd Sección 1)". unix.com . 24 de mayo de 2001 . Consultado el 15 de julio de 2014 .
  44. ^ "CS107 Valgrind Memcheck". web.stanford.edu . Consultado el 23 de junio de 2023 .
  45. ^ Hastings, Reed; Joyce, Bob. "Purify: detección rápida de fugas de memoria y errores de acceso" (PDF) . Pure Software Inc .: 9.
  46. ^ Dale, Nell B.; Weems, Chip (2014). Programación y resolución de problemas con C++ (6.ª ed.). Burlington, Massachusetts: Jones & Bartlett Learning. ISBN 978-1449694289.OCLC 894992484  .
  47. ^ "C – la madre de todos los idiomas". Academia de TIC en IITK . 13 de noviembre de 2018. Archivado desde el original el 31 de mayo de 2021. Consultado el 11 de octubre de 2022 .
  48. ^ "1. Extender Python con C o C++". Documentación de Python 3.10.7 . Archivado desde el original el 5 de noviembre de 2012 . Consultado el 11 de octubre de 2022 .
  49. ^ Conrad, Michael (22 de enero de 2018). «Una descripción general del motor Perl 5». Opensource.com . Archivado desde el original el 26 de mayo de 2022. Consultado el 11 de octubre de 2022 .
  50. ^ "De C y C++ a Ruby". Lenguaje de programación Ruby . Archivado desde el original el 12 de agosto de 2013. Consultado el 11 de octubre de 2022 .
  51. ^ Para, Michael (3 de agosto de 2022). "¿Qué es PHP? Cómo escribir tu primer programa PHP". freeCodeCamp . Archivado desde el original el 4 de agosto de 2022 . Consultado el 11 de octubre de 2022 .
  52. ^ Libro de consulta del Dr. Dobb . Estados Unidos: Miller Freeman, Inc. Noviembre-diciembre de 1995.
  53. ^ "Uso de C para programación CGI". linuxjournal.com. 1 de marzo de 2005. Archivado desde el original el 13 de febrero de 2010. Consultado el 4 de enero de 2010 .
  54. ^ Perkins, Luc (17 de septiembre de 2013). «Desarrollo web en C: ¿una locura? ¿O una locura como un zorro?». Medium . Archivado desde el original el 4 de octubre de 2014. Consultado el 8 de abril de 2022 .
  55. ^ Munoz, Daniel. "Después de todos estos años, el mundo todavía funciona con programación en C". Blog de ingeniería de Toptal . Consultado el 17 de noviembre de 2023 .
  56. ^ Metz, Cade. "Dennis Ritchie: Los hombros sobre los que se apoyaba Steve Jobs". Wired . Archivado desde el original el 12 de abril de 2022. Consultado el 19 de abril de 2022 .
  57. ^ corob-msft (31 de marzo de 2022). «Directivas Pragma y las palabras clave __pragma y _Pragma». Microsoft Learn . Archivado desde el original el 24 de septiembre de 2022. Consultado el 24 de septiembre de 2022 .
  58. ^ "Pragmas (El preprocesador de C)". GCC, la colección de compiladores de GNU . Archivado desde el original el 17 de junio de 2002. Consultado el 24 de septiembre de 2022 .
  59. ^ "Pragmas". Guía y referencia para desarrolladores del compilador clásico de Intel C++ . Intel. Archivado desde el original el 10 de abril de 2022 . Consultado el 10 de abril de 2022 .
  60. ^ "Elogio del preprocesador C". apenwarr . 13 de agosto de 2007 . Consultado el 9 de julio de 2023 .
  61. ^ Roberts, Eric S. (21 de marzo de 1989). "Implementación de excepciones en C" (PDF) . DEC Systems Research Center . SRC-RR-40. Archivado (PDF) del original el 15 de enero de 2017. Consultado el 4 de enero de 2022 .
  62. ^ McMillan, Robert (1 de agosto de 2013). "¿Está perdiendo Java su poder?". Wired . Archivado desde el original el 15 de febrero de 2017. Consultado el 5 de marzo de 2017 .
  63. ^ O'Regan, Gerard (24 de septiembre de 2015). Pilares de la informática: un compendio de empresas tecnológicas clave seleccionadas . Springer. ISBN 978-3319214641.OCLC 922324121  .
  64. ^ Rauchwerger, Lawrence (2004). Lenguajes y compiladores para computación paralela: 16.º taller internacional, LCPC 2003, College Station, TX, EE. UU., 2 al 4 de octubre de 2003: artículos revisados . Springer. ISBN 978-3540246442.OCLC 57965544  .
  65. ^ Stroustrup, Bjarne (1993). "A History of C++: 1979–1991" (PDF) . Archivado (PDF) del original el 2 de febrero de 2019. Consultado el 9 de junio de 2011 .

Fuentes

  • Ritchie, Dennis M. (marzo de 1993). "El desarrollo del lenguaje C". ACM SIGPLAN Notices . 28 (3). ACM: 201–208. doi : 10.1145/155360.155580 .
    • Por cortesía del autor, también en Ritchie, Dennis M. "Chistory". www.bell-labs.com . Consultado el 29 de marzo de 2022 .
  • Ritchie, Dennis M. (1993). "El desarrollo del lenguaje C". Segunda conferencia SIGPLAN de la ACM sobre la historia de los lenguajes de programación (HOPL-II) . ACM . pp. 201–208. doi :10.1145/154766.155580. ISBN . 0-89791-570-4Archivado desde el original el 11 de abril de 2019 . Consultado el 4 de noviembre de 2014 .
  • Kernighan, Brian W. ; Ritchie, Dennis M. (1988). El lenguaje de programación C (2.ª ed.). Prentice Hall . ISBN 0-13-110362-8.

Lectura adicional

  • Plauger, PJ (1992). La biblioteca de C estándar (1.ª edición). Prentice Hall. ISBN 978-0131315099. (fuente)
  • Banahan, M.; Brady, D.; Doran, M. (1991). El libro C: Presentación del estándar ANSI C (2.ª edición). Addison-Wesley. ISBN 978-0201544336. (gratis)
  • Feuer, Alan R. (1985). El libro de rompecabezas C (1.ª edición). Prentice Hall. ISBN 0131099345.
  • Harbison, Samuel; Steele, Guy Jr. (2002). C: A Reference Manual (5.ª edición). Pearson. ISBN 978-0130895929. (archivo)
  • King, KN (2008). Programación en C: un enfoque moderno (2.ª edición). WW Norton. ISBN 978-0393979503. (archivo)
  • Griffiths, David; Griffiths, Dawn (2012). Head First C (1.ª edición). O'Reilly. ISBN 978-1449399917.
  • Perry, Greg; Miller, Dean (2013). Programación en C: Guía para principiantes absolutos (3.ª edición). ISBN . 978-0789751980.
  • Deitel, Paul; Deitel, Harvey (2015). C: Cómo programar (8 ed.). Pearson. ISBN 978-0133976892.
  • Gustedt, Jens (2019). Modern C (2.ª ed.). Manning. ISBN 978-1617295812. (gratis)
  • Sitio web oficial del Grupo de trabajo ISO C
    • ISO/IEC 9899, ​​documentos oficiales C disponibles públicamente, incluido el fundamento C99
    • "C99 con correcciones técnicas TC1, TC2 y TC3 incluidas" (PDF) . Archivado (PDF) del original el 25 de octubre de 2007. (3,61 MB)
  • Preguntas frecuentes sobre comp.lang.c
  • Una historia de C, por Dennis Ritchie
  • Referencia y ejemplos de la biblioteca C
Obtenido de "https://es.wikipedia.org/w/index.php?title=C_(lenguaje_de_programación)&oldid=1258143572"