I. ¿Qué es C?
C es un lenguaje de programación generalista creado en 1972 para el sistema operativo UNIX. El propio sistema y la mayoría de sus programas complementarios están escritos en C. Sin embargo, no está ligado exclusivamente a UNIX y se puede usar en cualquier ordenador o sistema. Se le suele llamar «lenguaje de programación de sistemas», ya que sirve para crear sistemas operativos y compiladores, además de todo tipo de software común.
C evolucionó a partir del lenguaje B (derivado de BCPL). Tanto B como BCPL son lenguajes sin tipos, mientras que C incorpora un sistema completo de tipos de datos.
II. Características principales
1) Amplia variedad de tipos de datos
Comparado con su antecesor B, C cuenta con una gran diversidad de tipos de datos.
Tipos básicos: caracteres, números enteros de varios tamaños, números de punto flotante (decimales)
Tipos derivados: punteros, arrays, estructuras y uniones. Los punteros permiten manipular direcciones de memoria directamente, independientemente de la arquitectura del hardware.
Reglas: Los operadores se combinan para formar expresiones; cualquier expresión como una asignación o una llamada a función puede ser una instrucción completa por sí sola.
2) Control completo del flujo del programa
Incluye bifurcaciones condicionales (if-else), selección múltiple (switch), dos tipos de bucles (while/for que comprueban la condición antes de ejecutarse, do que la comprueba después de ejecutarse), salida anticipada de bucles (break) y más. Estas instrucciones de flujo permiten crear lógicas de programa muy variadas.
3) Funciones
Una función es un conjunto empaquetado de pasos de operación fijos. Le das un nombre, y cada vez que llames ese nombre, ejecutará automáticamente todo el proceso completo.
Un ejemplo de la vida cotidiana:
Supongamos que «hornear pan» es una función.
No tienes que repetir todo el proceso cada vez que quieras pan: amasar la masa → dar forma → hornear.
Solo tienes que escribir «hornear pan» y todo el procedimiento se ejecuta automáticamente; esto se llama llamar a una función.
Si quieres hornear pan dos veces, basta con llamar la función «hornear pan» dos veces.
Traduciendo este concepto al lenguaje C:
La función
printftiene todo el código necesario para mostrar texto en pantalla. Solo tienes que escribirprintf("Hola")sin tener que controlar la pantalla paso a paso manualmente.
Las funciones pueden devolver todo tipo de datos: números enteros, estructuras, punteros y más.
Admite llamadas recursivas (una función se llama a sí misma). Las variables locales dentro de una función se vuelven a crear en cada invocación; no se pueden definir funciones anidadas dentro de otras, pero sí se pueden declarar variables dentro de bloques de código separados.
El código fuente de un proyecto se puede dividir en varios archivos .c y compilarlos por separado.
Las variables tienen tres ámbitos de visibilidad: solo dentro de una función, global pero limitado a un único archivo fuente, o visible para todo el programa.
4) El preprocesador
Antes de la compilación se ejecuta el preprocesamiento: sustitución masiva de texto mediante macros, importación de otros archivos de código, compilación condicional de fragmentos seleccionados.
El preprocesador se encarga de procesar órdenes que no forman parte de la sintaxis básica del lenguaje antes de compilar realmente. Estas herramientas extras existen para agilizar el desarrollo y mejorar la eficiencia, principalmente mediante macros. Lo veremos en detalle en capítulos posteriores.
III. Un lenguaje minimalista de bajo nivel
Aquí «bajo nivel» no es un término peyorativo: C solo manipula los elementos nativos del ordenador: caracteres, valores numéricos y direcciones de memoria, aprovechando la lógica aritmética integrada en el hardware para ofrecer un rendimiento de ejecución muy alto.
Es decir, puede interactuar con los componentes internos más profundos del ordenador. En comparación con otros lenguajes, C permite acceder directamente a direcciones de memoria e incluso controlar hardware.
Pocas funcionalidades nativas; las capacidades complejas se implementan mediante bibliotecas
C no cuenta con soporte nativo integrado para cadenas de caracteres, arrays, colecciones, archivos, entrada y salida:
No se puede manipular una cadena o array completo en una sola operación; solo las estructuras permiten copiar todo su contenido.
No existe gestión automática de memoria ni recolector de basura: el desarrollador debe reservar y liberar memoria manualmente.
No hay palabras clave nativas como read/write; para imprimir texto o leer entradas del teclado hay que llamar obligatoriamente funciones de biblioteca.
Solo ofrece flujos de ejecución de un solo hilo, sin soporte nativo para multitarea, operaciones paralelas, sincronización o corrutinas.
Una biblioteca es simplemente una colección de funciones preescritas en C u otros lenguajes. Los desarrolladores pueden llamar estas funciones listas para implementar funcionalidades sin tener que programar todo desde cero.
Aunque muchas funciones requieren llamar a bibliotecas, el lenguaje en sí es compacto y con reglas sencillas, por lo que es fácil de aprender y dominar completamente.
IV. Estandarización de C: ANSI C (1988)
La estandarización surgió porque al principio C se usaba de forma extendida y cada empresa creaba sus propias variantes, sin reglas unificadas. Se creó un organismo especializado para definir una normativa común, igual que las normas que regulan los puertos USB o los enchufes eléctricos.
ANSI = American National Standards Institute
Explicación
El Instituto Nacional Estadounidense de Estándares es una organización privada de normalización de EE.UU. No produce software ni escribe código fuente, sino que crea especificaciones uniformes para todas las industrias: fabricación, electrónica, informática y lenguajes de programación.
¿Qué es ANSI C?
En 1983, ANSI formó un comité para unificar la sintaxis del lenguaje C, y a finales de 1988 publicó la primera especificación oficial del lenguaje, conocida como ANSI C (también llamada C89).
V. Complemento de la norma ANSI: La biblioteca estándar
La norma introdujo una biblioteca estándar unificada que proporciona utilidades multiplataforma para acceso a archivos, entrada y salida formateada, reserva de memoria, manipulación de cadenas y más, accesible mediante archivos de cabecera estandarizados.
La sintaxis nativa de C es intencionalmente minimalista, solo cubre elementos básicos como variables, condicionales, bucles, funciones y punteros. No tiene ninguna funcionalidad integrada de forma nativa para imprimir texto, leer el teclado, gestionar archivos, realizar cálculos matemáticos o manipular cadenas.
La especificación ANSI C define un conjunto universal de funciones de utilidad compatible con todos los compiladores en todos los sistemas operativos: este conjunto de herramientas se llama la biblioteca estándar.
Para acceder a las funciones de biblioteca, los desarrolladores importan archivos de cabecera con la sintaxis #include nombrearchivo.h.
Ejemplos:
#include <stdio.h> // Biblioteca E/S: printf (imprimir texto), scanf (leer entrada de usuario)
#include <stdlib.h> // Reserva de memoria, salida del programa, generación de números aleatorios
#include <string.h> // Copia y comparación de cadenas de caracteres
#include <math.h> // Funciones matemáticas como sin(), sqrt()Lenguaje del código: HTML, XML (xml)
Antes de la norma ANSI, las funciones de impresión funcionaban distinto en UNIX y Windows, causando errores al portar código entre sistemas. Después de la biblioteca estándar, un código como printf("hola") se ejecuta igual en Windows, Linux y macOS sin modificaciones, reduciendo mucho el trabajo de los desarrolladores y acelerando la expansión mundial de C.
¿Con qué lenguajes se desarrolló la biblioteca estándar?
La mayoría de sus funcionalidades están implementadas en C, con una pequeña parte que usa ensamblador y otros lenguajes de bajo nivel.
Las funciones que no interactúan directamente con hardware o el sistema operativo, como la copia de cadenas strcpy, operaciones matemáticas o copia de bloques de memoria, están escritas casi totalmente en C puro.
Las operaciones que interactúan directamente con el hardware o el núcleo del sistema operativo no se pueden hacer solo con C; requieren lenguajes complementarios de bajo nivel, principalmente ensamblador.
VI. Portabilidad y seguridad de tipos
El mismo código fuente se puede compilar y ejecutar en distintos sistemas operativos con pocos cambios o sin modificaciones.
Después de leer esta introducción, deberías tener una comprensión básica de C. Si algunos conceptos siguen sin quedar claros, no te preocupes: las explicaciones solo con texto suelen ser difíciles de asimilar. En los capítulos siguientes analizaremos cada tema con ejemplos prácticos de código para consolidar estas ideas.