Biblioteca estándar de C (libc) |
---|
Temas generales |
Encabezados varios |
La biblioteca estándar de C , a veces denominada libc , [ cita requerida ] es la biblioteca estándar para el lenguaje de programación C , como se especifica en el estándar ISO C. [1] A partir del estándar ANSI C original , se desarrolló al mismo tiempo que la especificación POSIX de la biblioteca C , que es un superconjunto de esta. [2] [3] Dado que ANSI C fue adoptado por la Organización Internacional de Normalización , [4] la biblioteca estándar de C también se denomina biblioteca ISO C. [ cita requerida ]
La biblioteca estándar de C proporciona macros , definiciones de tipos y funciones para tareas como manipulación de cadenas , cálculo matemático, procesamiento de entrada/salida, gestión de memoria y entrada/salida .
La interfaz de programación de aplicaciones (API) de la biblioteca estándar de C se declara en una serie de archivos de encabezado . Cada archivo de encabezado contiene una o más declaraciones de funciones, definiciones de tipos de datos y macros.
Después de un largo período de estabilidad, se agregaron tres nuevos archivos de encabezado ( iso646.h
, wchar.h
, y ) con el Anexo Normativo 1 (NA1), una adición al Estándar C ratificado en 1995. Se agregaron seis archivos de encabezado más ( , , , , y ) con C99 , una revisión del Estándar C publicada en 1999, y cinco archivos más ( , , , y ) con C11 en 2011. En total, ahora hay 29 archivos de encabezado:wctype.h
complex.h
fenv.h
inttypes.h
stdbool.h
stdint.h
tgmath.h
stdalign.h
stdatomic.h
stdnoreturn.h
threads.h
uchar.h
Nombre | De | Descripción |
---|---|---|
<assert.h> | Declara la macro assert , utilizada para ayudar a detectar errores lógicos y otros tipos de errores mientras se depura un programa. | |
<complex.h> | C99 | Define un conjunto de funciones para manipular números complejos . |
<ctype.h> | Define un conjunto de funciones utilizadas para clasificar caracteres por sus tipos o para convertir entre mayúsculas y minúsculas de una manera independiente del conjunto de caracteres utilizado (normalmente ASCII o una de sus extensiones, aunque también se conocen implementaciones que utilizan EBCDIC ). | |
<errno.h> | Para probar los códigos de error informados por las funciones de la biblioteca. | |
<fenv.h> | C99 | Define un conjunto de funciones para controlar el entorno de punto flotante . |
<float.h> | Define constantes macro que especifican las propiedades específicas de la implementación de la biblioteca de punto flotante . | |
<inttypes.h> | C99 | Define tipos enteros de ancho exacto . |
<iso646.h> | NA1 | Define varias macros que implementan formas alternativas de expresar varios tokens estándar. Para programación en conjuntos de caracteres variantes de ISO 646 . |
<limits.h> | Define constantes macro que especifican las propiedades específicas de la implementación de los tipos enteros. | |
<locale.h> | Define funciones de localización . | |
<math.h> | Define funciones matemáticas comunes . | |
<setjmp.h> | Declara las macros setjmp y longjmp , que se utilizan para salidas no locales. | |
<signal.h> | Define funciones de manejo de señales . | |
<stdalign.h> | C11 | Para consultar y especificar la alineación de objetos. |
<stdarg.h> | Para acceder a un número variable de argumentos pasados a funciones. | |
<stdatomic.h> | C11 | Para operaciones atómicas sobre datos compartidos entre subprocesos. |
<stdbool.h> | C99 | Define un tipo de datos booleano . |
<stddef.h> | Define varios tipos y macros útiles . | |
<stdint.h> | C99 | Define tipos enteros de ancho exacto . |
<stdio.h> | Define las funciones principales de entrada y salida. | |
<stdlib.h> | Define funciones de conversión numérica , funciones de generación de números pseudoaleatorios , asignación de memoria y funciones de control de procesos. | |
<stdnoreturn.h> | C11 | Para especificar funciones que no retornan |
<string.h> | Define funciones de manejo de cadenas | |
<tgmath.h> | C99 | Define funciones matemáticas de tipo genérico . |
<threads.h> | C11 | Define funciones para administrar múltiples subprocesos , mutexes y variables de condición. |
<time.h> | Define funciones de manejo de fecha y hora. | |
<uchar.h> | C11 | Tipos y funciones para manipular caracteres Unicode |
<wchar.h> | NA1 | Define funciones de manejo de cadenas anchas |
<wctype.h> | NA1 | Define un conjunto de funciones utilizadas para clasificar caracteres anchos por sus tipos o para convertir entre mayúsculas y minúsculas. |
Tres de los archivos de encabezado ( complex.h
, stdatomic.h
, y threads.h
) son características condicionales que las implementaciones no están obligadas a soportar.
El estándar POSIX agregó varios encabezados C no estándar para funciones específicas de Unix. Muchos de ellos se han incorporado a otras arquitecturas. Algunos ejemplos son fcntl.h
y unistd.h
. Varios otros grupos están utilizando otros encabezados no estándar: la biblioteca C de GNU tiene alloca.h
y OpenVMS tiene la va_count()
función .
En los sistemas tipo Unix, la documentación autorizada de la API se proporciona en forma de páginas de manual . En la mayoría de los sistemas, las páginas de manual sobre las funciones de la biblioteca estándar se encuentran en la sección 3; la sección 7 puede contener algunas páginas más genéricas sobre conceptos subyacentes (por ejemplo, man 7 math_error
en Linux ).
Los sistemas tipo Unix suelen tener una biblioteca C en forma de biblioteca compartida , pero los archivos de encabezado (y la cadena de herramientas del compilador) pueden faltar en una instalación, por lo que el desarrollo en C puede no ser posible. La biblioteca C se considera parte del sistema operativo en sistemas tipo Unix; además de las funciones especificadas por el estándar C, incluye otras funciones que son parte de la API del sistema operativo, como las funciones especificadas en el estándar POSIX . Las funciones de la biblioteca C, incluidas las del estándar ISO C, son ampliamente utilizadas por los programas y se consideran no solo una implementación de algo en el lenguaje C, sino también parte de facto de la interfaz del sistema operativo. Los sistemas operativos tipo Unix generalmente no pueden funcionar si se borra la biblioteca C. Esto es cierto para las aplicaciones que están vinculadas dinámicamente en lugar de estáticamente. Además, el núcleo en sí (al menos en el caso de Linux) opera independientemente de cualquier biblioteca.
En Microsoft Windows, las bibliotecas dinámicas del sistema central ( DLL ) proporcionan una implementación de la biblioteca estándar de C para el compilador Microsoft Visual C++ v6.0; la biblioteca estándar de C para las versiones más nuevas del compilador Microsoft Visual C++ es proporcionada por cada compilador individualmente, así como por paquetes redistribuibles . Las aplicaciones compiladas escritas en C están enlazadas estáticamente con una biblioteca de C, o enlazadas a una versión dinámica de la biblioteca que se envía con estas aplicaciones, en lugar de depender de que estén presentes en los sistemas de destino. Las funciones en la biblioteca de C de un compilador no se consideran interfaces para Microsoft Windows.
Existen muchas implementaciones de bibliotecas C, que se incluyen con varios sistemas operativos y compiladores de C. Algunas de las implementaciones más populares son las siguientes:
Algunos compiladores (por ejemplo, GCC [7] ) proporcionan versiones integradas de muchas de las funciones de la biblioteca estándar de C; es decir, las implementaciones de las funciones se escriben en el archivo de objeto compilado y el programa llama a las versiones integradas en lugar de las funciones del archivo de objeto compartido de la biblioteca de C. Esto reduce la sobrecarga de llamadas a funciones, especialmente si las llamadas a funciones se reemplazan con variantes en línea , y permite otras formas de optimización (ya que el compilador conoce las características de flujo de control de las variantes integradas), pero puede causar confusión durante la depuración (por ejemplo, las versiones integradas no se pueden reemplazar con variantes instrumentadas ).
Sin embargo, las funciones incorporadas deben comportarse como funciones ordinarias de acuerdo con ISO C. La implicación principal es que el programa debe ser capaz de crear un puntero a estas funciones tomando su dirección e invocar la función por medio de ese puntero. Si dos punteros a la misma función se derivan en dos unidades de traducción diferentes en el programa, estos dos punteros deben compararse como iguales; es decir, la dirección se obtiene al resolver el nombre de la función, que tiene un enlace externo (a nivel de programa).
En FreeBSD [8] y glibc, [9] algunas funciones como sin() no están enlazadas de forma predeterminada y, en su lugar, se incluyen en la biblioteca matemática libm . Si se utiliza alguna de ellas, se debe proporcionar al enlazador la directiva -lm
. POSIX requiere que el compilador c99 admita -lm
, y que las funciones declaradas en los encabezados math.h
, complex.h
, y fenv.h
estén disponibles para enlazar si -lm
se especifica , pero no especifica si las funciones están enlazadas de forma predeterminada. [10] musl satisface este requisito poniendo todo en una única biblioteca libc y proporcionando una libm vacía. [11]
Según el estándar C, la macro __STDC_HOSTED__
se debe definir como 1 si la implementación está alojada. Una implementación alojada tiene todos los encabezados especificados por el estándar C. Una implementación también puede ser independiente , lo que significa que estos encabezados no estarán presentes. Si una implementación es independiente , se debe definir __STDC_HOSTED__
como 0 .
Algunas funciones de la biblioteca estándar de C son conocidas por tener vulnerabilidades de desbordamiento de búfer y, en general, por fomentar una programación llena de errores desde su adopción. [a] Los elementos más criticados son:
strcpy()
y strcat()
, por falta de verificación de límites y posibles desbordamientos de búfer si los límites no se verifican manualmente;printf()
Familia de rutinas que estropean la pila de ejecución cuando la cadena de formato no coincide con los argumentos proporcionados. Esta falla fundamental creó una clase completa de ataques: ataques de cadena de formato ;gets()
y scanf()
familia de rutinas de E/S, por falta de verificación de longitud de entrada (ya sea alguna o fácil).Excepto en el caso extremo de gets()
, todas las vulnerabilidades de seguridad se pueden evitar introduciendo código auxiliar para realizar la gestión de memoria, comprobación de límites, comprobación de entrada, etc. Esto se suele hacer en forma de envoltorios que hacen que las funciones de la biblioteca estándar sean más seguras y fáciles de usar. Esto se remonta al libro The Practice of Programming de B. Kernighan y R. Pike, donde los autores suelen utilizar envoltorios que imprimen mensajes de error y abandonan el programa si se produce un error.
El comité ISO C publicó los informes técnicos TR 24731-1 [12] y está trabajando en el TR 24731-2 [13] para proponer la adopción de algunas funciones con verificación de límites y asignación automática de búfer, respectivamente. El primero recibió severas críticas y algunos elogios [14] [15] , mientras que el segundo tuvo una respuesta mixta.
A pesar de las preocupaciones, TR 24731-1 se integró en la ruta de estándares C en ISO/IEC 9899:2011 (C11), Anexo K ( Interfaces de verificación de límites ), y se implementó aproximadamente en la biblioteca de tiempo de ejecución C/++ (CRT) de Microsoft para las plataformas Win32 y Win64.
(De manera predeterminada, los compiladores C y C++ de Microsoft Visual Studio emiten advertencias cuando se utilizan funciones antiguas e "inseguras". Sin embargo, la implementación de Microsoft de TR 24731-1 es sutilmente incompatible tanto con TR 24731-1 como con Annex K, [16] por lo que es común que los proyectos portables deshabiliten o ignoren estas advertencias. Se pueden deshabilitar directamente emitiendo
#pragma advertencia(deshabilitar: 4996)
antes/alrededor del sitio de llamada en cuestión, o indirectamente mediante la emisión
#define _CRT_SECURE_SIN_ADVERTENCIAS 1
antes de incluir cualquier encabezado. [17] La opción de línea de comandos /D_CRT_NO_SECURE_WARNINGS=1
debería tener el mismo efecto que esta #define
.)
La strerror()
rutina es criticada por no ser segura para los subprocesos y por ser vulnerable a las condiciones de carrera .
El manejo de errores de las funciones en la biblioteca estándar de C no es consistente y a veces resulta confuso. Según la página del manual de Linux math_error
, "La situación actual (versión 2.8) bajo glibc es confusa. La mayoría de las funciones (pero no todas) generan excepciones en caso de errores. Algunas también establecen errno . Unas pocas funciones establecen errno , pero no generan una excepción. Unas pocas funciones no hacen ninguna de las dos cosas". [18]
El lenguaje C original no proporcionaba funciones integradas como operaciones de E/S, a diferencia de los lenguajes tradicionales como COBOL y Fortran . [ cita requerida ] Con el tiempo, las comunidades de usuarios de C compartieron ideas e implementaciones de lo que ahora se denomina bibliotecas estándar de C. Muchas de estas ideas se incorporaron eventualmente a la definición del lenguaje C estandarizado.
Tanto Unix como C fueron creados en los Laboratorios Bell de AT&T a finales de los años 60 y principios de los 70. Durante los años 70, el lenguaje C se hizo cada vez más popular. Muchas universidades y organizaciones comenzaron a crear sus propias variantes del lenguaje para sus propios proyectos. A principios de los años 80, los problemas de compatibilidad entre las diversas implementaciones de C se hicieron evidentes. En 1983, el Instituto Nacional Estadounidense de Estándares (ANSI) formó un comité para establecer una especificación estándar de C conocida como " ANSI C ". Este trabajo culminó en la creación del llamado estándar C89 en 1989. Parte del estándar resultante fue un conjunto de bibliotecas de software llamado biblioteca estándar ANSI C.
POSIX , así como SUS , especifican una serie de rutinas que deberían estar disponibles además de las de la biblioteca estándar básica de C. La especificación POSIX incluye archivos de encabezado para, entre otros usos, multi-threading , networking y expresiones regulares . Estos se implementan a menudo junto con la funcionalidad de la biblioteca estándar de C, con distintos grados de proximidad. Por ejemplo, glibc implementa funciones como fork
within libc.so
, pero antes de que NPTL se fusionara con glibc, constituía una biblioteca separada con su propio argumento de indicador de enlazador. A menudo, esta funcionalidad especificada por POSIX se considerará parte de la biblioteca; la biblioteca básica de C puede identificarse como la biblioteca ANSI o ISO de C.
BSD libc es un superconjunto de la biblioteca estándar POSIX compatible con las bibliotecas C incluidas en los sistemas operativos BSD, como FreeBSD , NetBSD , OpenBSD y macOS . BSD libc tiene algunas extensiones que no están definidas en el estándar original, muchas de las cuales aparecieron por primera vez en la versión 4.4BSD de 1994 (la primera que se desarrolló en gran medida después de que se publicara el primer estándar en 1989). Algunas de las extensiones de BSD libc son:
sys/tree.h
– contiene una implementación de árbol rojo-negro y árbol de dispersión [19] [20]sys/queue.h
– implementaciones de listas enlazadas , colas , cola de cola, etc. [21] [22]fgetln()
– definido en stdio.h
. Esto se puede utilizar para leer un archivo línea por línea. [23] [24] [25]fts.h
– contiene algunas funciones para recorrer una jerarquía de archivos [26] [27]db.h
– algunas funciones para conectarse a la base de datos Berkeley [28] [29]strlcat()
y strlcpy()
– alternativas seguras para strncat()
y strncpy()
[30] [31] [32] [33] [34]err.h
– contiene algunas funciones para imprimir mensajes de error formateados [35] [36]vis.h
– contiene la vis()
función. Esta función se utiliza para mostrar caracteres no imprimibles en un formato visual. [37] [38] [39]Algunos lenguajes incluyen la funcionalidad de la biblioteca estándar de C en sus propias bibliotecas. La biblioteca puede adaptarse para que se ajuste mejor a la estructura del lenguaje, pero la semántica operativa se mantiene similar.
El lenguaje C++ incorpora la mayoría de las construcciones de la biblioteca estándar de C, excluyendo la maquinaria específica de C. Las funciones de la biblioteca estándar de C se exportan desde la biblioteca estándar de C++ de dos maneras.
Para compatibilidad con versiones anteriores y cruzadas de C y C++ anterior al estándar, se puede acceder a las funciones en el espacio de nombres global ( : :), después de incluir el nombre del encabezado estándar de C como en C. [40] Por lo tanto, el programa C++98#include
#include <stdio.h> int main () { return :: puts ( "¡Hola, mundo!" ) == EOF ; }
Debería mostrar un comportamiento (aparentemente) idéntico al programa C95
#include <stdio.h> int main ( void ) { return puts ( "¡Hola, mundo!" ) == EOF ; }
A partir de C++98 , las funciones de C también están disponibles en el espacio de nombres ::std (por ejemplo, C printf como C++ ::std::printf , atoi como ::std::atoi , feof como ::std::feof ), al incluir header en lugar del header de C correspondiente . Por ejemplo, <cstdio> sustituye a <stdio.h> y <cmath> a <math.h> ; observe la falta de la extensión .h en los nombres de encabezado de C++.<chdrname>
<hdrname.h>
Por lo tanto, un programa C++≥98 equivalente (generalmente preferible) a los dos anteriores es:
#include <cstdio> int main () { return std :: puts ( "Hola, mundo" ) == EOF ; }
Se puede emitir una declaración arriba o dentro de main para aplicar el prefijo ::std:: automáticamente, aunque generalmente se considera una mala práctica usarlo globalmente en los encabezados porque contamina el espacio de nombres global. [41]using namespace ::std
Faltan algunas de las versiones C++≥98 de los encabezados de C; por ejemplo, C≥11 <stdnoreturn.h> y <threads.h> no tienen contrapartes C++. [42]
Otros se reducen a marcadores de posición, como (hasta C++20 ) <ciso646> para C95 <iso646.h> , todas cuyas macros necesarias se representan como palabras clave en C++98. Las construcciones sintácticas específicas de C generalmente no son compatibles, incluso si su encabezado lo es. [43]
Existen varios encabezados C principalmente para compatibilidad con C++, y estos tienden a estar casi vacíos en C++. Por ejemplo, C99 – 17 <stdbool.h> requiere solo
#define bool _Bool #define falso 0 #define verdadero 1 #define __bool_true_false_are_defined 1
para simular soporte para las palabras claves bool , false y true de C++98 en C. C++11 requiere <stdbool.h> y <cstdbool> para compatibilidad, pero todo lo que necesitan definir es __bool_true_false_are_defined . C23 deja obsoleta la antigua palabra clave _Bool a favor de las nuevas palabras clave bool , false y true equivalentes a C++98 , por lo que los encabezados <stdbool.h> / <cstdbool> de C≥23 y C++≥11 son completamente equivalentes. (En particular, C23 no requiere ninguna macro __STDC_VERSION_BOOL_H__ para <stdbool.h> ).
Se prefiere el acceso a las funciones de la biblioteca C a través del espacio de nombres ::std y los nombres de encabezado de C++≥98 siempre que sea posible. Para fomentar la adopción, C++98 deja obsoletos los nombres de encabezado de C ( *.h ), por lo que es posible que el uso de encabezados de compatibilidad de C haga que un preprocesador de C++98–20 especialmente estricto genere un diagnóstico de algún tipo. Sin embargo, C++23 (inusualmente) deja obsoletos estos encabezados, por lo que las implementaciones/modos de C++ más nuevos no deberían quejarse sin que se les pida específicamente que lo hagan. [44]
Otros lenguajes adoptan un enfoque similar, colocando las funciones/rutinas de compatibilidad de C bajo un espacio de nombres común; estos incluyen D , Perl y Ruby .
CPython incluye envoltorios para algunas de las funciones de la biblioteca C en su propia biblioteca común, y también otorga acceso más directo a las funciones y variables C a través de su paquete ctypes . [45]
De manera más general, Python 2. x especifica que los objetos de archivo integrados se “implementan utilizando el paquete stdio de C [46] ”, y se hace referencia frecuente a los comportamientos de la biblioteca estándar de C; se espera que las operaciones disponibles ( open
, read
, write
, etc.) tengan el mismo comportamiento que las funciones C correspondientes ( fopen
, fread
, fwrite
, etc.).
Sin embargo, la especificación de Python 3 depende considerablemente menos de los detalles específicos de C que Python 2 .
Rust ofrece el paquete libc , que permite utilizar varias funciones de biblioteca y definiciones de tipos estándar de C (y otras). [47]
La biblioteca estándar de C es pequeña en comparación con las bibliotecas estándar de otros lenguajes. La biblioteca de C proporciona un conjunto básico de funciones matemáticas, manipulación de cadenas, conversión de tipos y E/S basada en archivos y consola. No incluye un conjunto estándar de " tipos de contenedor " como la biblioteca de plantillas estándar de C++ , y mucho menos los kits de herramientas de interfaz gráfica de usuario (GUI) completos, las herramientas de red y la profusión de otras funciones que Java y .NET Framework proporcionan como estándar. La principal ventaja de la pequeña biblioteca estándar es que proporcionar un entorno C ISO funcional es mucho más fácil que con otros lenguajes y, en consecuencia, portar C a una nueva plataforma es comparativamente fácil.
gets()
fue creado ya en 1988.Una sola
declaración en un solo archivo de encabezado en un proyecto complejo puede arruinar la administración del espacio de nombres para todo el proyecto.
Por lo tanto, ¡no se permiten declaraciones [ ] de nivel superior
en un archivo de encabezado!
using namespace std;
using namespace
Los objetos de archivo se implementan utilizando el paquete
stdio
de C y se pueden crear con la función incorporada
.
open()