Especificadores para clases de almacenamiento
Los siguientes especificadores determinan la duración de almacenamiento y el tipo de enlazamiento para objetos y funciones:
auto- duración automática y sin enlaceregister- duración automática y sin enlace;no se puede tomar la dirección de esta variablestatic- duración estática y enlace interno (a menos que sea en el ámbito del bloque)extern- duración estática y enlace externo (a menos que ya se haya declarado como interno)
|
(desde C11) |
Explicación
Los especificadores para clases de almacenamiento aparecen en las declaraciones. Como máximo se puede utilizar un especificador, a excepción de _Thread_local que se puede combinar con static o extern para ajustar el enlace (desde C11). Los especificadores para clases de almacenamiento determinan dos propiedades independientes de los nombres que declaran: duración del almacenamiento y enlace.
auto sólo está permitido para los objetos declarados en el ámbito del bloque (excepto las listas de parámetros de función). Este indica la duración del almacenamiento automático y la ausencia de enlaces, que son los valores por defecto para este tipo de declaraciones.register sólo está permitido para los objetos declarados en el ámbito del bloque, incluidas las listas de parámetros de funciones. Este indica la duración de almacenamiento sea automático y sin enlaces (que es el valor por defecto para este tipo de declaraciones), pero adicionalmente indica al optimizador que almacene el valor de esta variable en un registro de la CPU si es posible. Independientemente de si esta optimización tiene lugar o no, , las variables declaradas como register no pueden ser usadas como argumentos para la adirección del operador, no pueden usar alignas (desde C11), y los matrices de register no son convertibles a punteros.static especifica tanto la duración del almacenamiento estático (a menos que se combine con _Thread_local) (desde C11) como el enlace interno (a menos que se utilice en el ámbito del bloque). Se puede utilizar con funciones en el ámbito de archivo y con variables tanto en el ámbito del archivo como de bloque, pero no en las listas de parámetros de funciones.extern especifica la duración del almacenamiento estático (a menos que se combine con _Thread_local) (desde C11) y el enlace externo. Se puede utilizar con declaraciones de función y de objeto tanto en el ámbito de archivo como en el de bloque (excluyendo las listas de parámetros de función). Si extern aparece en una redeclaración de un identificador que ya fue declarado con enlace interno, el enlace sigue siendo interno. De lo contrario (si la declaración previa era externa, sin vinculación, o no está en el ámbito), la vinculación es externa.|
5) _Thread_local indica la duración del almacenamiento del hilo. No se puede utilizar con declaraciones de función. Si se utiliza en una declaración de un objeto, debe estar presente en todas las declaraciones del mismo objeto. Si se utiliza en una declaración de ámbito de bloque, debe combinarse con una conexión ya sea static o extern para decidir el tipo de enlace.
|
(desde C11) |
Si no se proporciona ningún especificador de clase de almacenamiento, los valores predeterminados son:
externpara todas las funcionesexternpara objetos en el ámbito de archivoautopara objetos en el ámbito del bloque
Para cualquier estructura o unión declarada con un especificador de clase de almacenamiento, la duración del almacenamiento (pero no la vinculación) se aplica a sus miembros, recursivamente.
Las declaraciones de función en el ámbito de aplicación del bloque pueden usar extern o bien ninguna . Las declaraciones de función en el ámbito de archivo pueden utilizar extern o static.
Los parámetros de función no pueden utilizar ningún especificador de clase de almacenamiento que no sea register. Tenga en cuenta que static tiene un significado especial en los parámetros de función del tipo matriz.
Duración del almacenamiento
Cada objeto tiene una propiedad llamada duración del almacenamiento, que limita el tiempo de vida del objeto. Hay cuatro tipos de duración de almacenamiento en C:
- Tiempo de almacenamiento automatic. El almacenamiento se asigna cuando se introduce el bloque en el que se declaró el objeto y se anula su asignación cuando se sale por cualquier medio (goto, return, llegar al final). Una excepción son los VLAs; su almacenamiento se asigna cuando se ejecuta la declaración, no en la entrada de bloque, y se desasigna cuando la declaración sale del ámbito, no que cuando se sale del bloque (desde C99). Si el bloque se introduce recursivamente, se realiza una nueva asignación para cada nivel de recursividad. Todos los parámetros de función y los objetos no
staticdel ámbito de bloque tienen esta duración de almacenamiento, así como los literales compuestos utilizados en el ámbito de bloque.
- Tiempo de almacenamiento automatic. El almacenamiento se asigna cuando se introduce el bloque en el que se declaró el objeto y se anula su asignación cuando se sale por cualquier medio (goto, return, llegar al final). Una excepción son los VLAs; su almacenamiento se asigna cuando se ejecuta la declaración, no en la entrada de bloque, y se desasigna cuando la declaración sale del ámbito, no que cuando se sale del bloque (desde C99). Si el bloque se introduce recursivamente, se realiza una nueva asignación para cada nivel de recursividad. Todos los parámetros de función y los objetos no
- Tiempo de almacenamiento static. La duración de almacenamiento es la ejecución completa del programa, y el valor almacenado en el objeto se inicializa sólo una vez, antes de la función main. Todos los objetos declarados
staticy todos los objetos con enlaces internos o externos que no sean declarados_Thread_local(desde C11) tienen esta duración de almacenamiento.
- Tiempo de almacenamiento static. La duración de almacenamiento es la ejecución completa del programa, y el valor almacenado en el objeto se inicializa sólo una vez, antes de la función main. Todos los objetos declarados
|
(desde C11) |
- Tiempo de almacenamientoallocated. El almacenamiento es asignado y desasignado a petición, utilizando funciones dinámicas de asignación de memoria.
Enlazado
El enlazado se refiere a la capacidad de un identificador (variable o función) para ser mencionado en otros ámbitos. Si una variable o función con el mismo identificador se declara en varios ámbitos, pero no puede ser referenciada desde todos ellos, entonces se generan varias instancias de la variable. Se reconocen los siguientes vínculos:
- sin enlazado. Sólo se puede hacer referencia al identificador desde el ámbito en el que se encuentra. Todos los parámetros de función y todas las variables de alcance de bloque que no son {tt|extern}} (incluidas las declaradas
static) tienen este enlace.
- sin enlazado. Sólo se puede hacer referencia al identificador desde el ámbito en el que se encuentra. Todos los parámetros de función y todas las variables de alcance de bloque que no son {tt|extern}} (incluidas las declaradas
- enlazado interno. El identificador se puede consultar desde todos los ámbitos de la unidad de traducción actual. Todos los identificadores de alcance de archivo
static(tanto funciones como variables) tienen este vínculo.
- enlazado interno. El identificador se puede consultar desde todos los ámbitos de la unidad de traducción actual. Todos los identificadores de alcance de archivo
- enlazado externo. El identificador se puede consultar desde cualquier otra unidad de traducción de todo el programa. Todas las funciones no
static, todas las variablesextern(a menos que se haya declarado anteriormentestatic) y todas las variables file-scope non-statictienen este vínculo.
- enlazado externo. El identificador se puede consultar desde cualquier otra unidad de traducción de todo el programa. Todas las funciones no
Si aparece el mismo identificador con enlaces internos y externos en la misma unidad de traducción, el comportamiento es indefinido. Esto es posible cuando se utilizan definiciones tentativas.
Enlaces y bibliotecas
| Esta sección está incompleta Razón: ¿Debería ser una entrada separada de nivel superior en c/language en Misceláneo? |
Las declaraciones con enlace externo suelen estar disponibles en los archivos de encabezado, de modo que todas las unidades de traducción que contienen #include en el archivo pueden referirse al mismo identificador que se define en otra parte.
Cualquier declaración con enlace interno que aparezca en un archivo de encabezado resulta en un objeto separado y distinto en cada unidad de traducción que incluya ese archivo.
Interfaz de biblioteca:
// flib.h
#ifndef FLIB_H
#define FLIB_H
void f(void); // declaración de función con enlace externo
extern int state; // declaración de la variable con enlace externo
static const int size = 5; // definición de una variable de sólo lectura con enlace interno
enum { MAX = 10 }; // definición de una constante
inline int sum (int a, int b) { return a+b; } // definición de la función inline
#endif // FLIB_H
Implementación de la biblioteca:
// flib.c
#include "flib.h"
static void local_f(int s) {} // definición con enlace interno (sólo se utiliza en este archivo)
static int local_state; // definición con enlace interno (sólo se utiliza en este archivo)
int state; // definición con enlace externo (utilizado por main.c)
void f(void) {local_f(state);} // definición con enlace externo (utilizado por main.c)
Código de la aplicación:
// main.c
#include "flib.h"
int main(void)
{
int x[MAX] = {size}; // utiliza la constante y la variable de sólo lectura
state = 7; // modifica el estado en flib.c
f(); // llama a f() en flib.c
}
Terminos clave
auto, register, static, extern, _Thread_local
Observaciones
El termino clave _Thread_local se utiliza normalmente a través de la práctica macro thread_local, definida en la cabecera threads.h.
El especificador typedef} se lista formalmente como un especificador de clase de almacenamiento en la gramática del lenguaje C, pero se utiliza para declarar nombres de tipos y no para especificar el tipo de almacenamiento.
Los nombres en el ámbito de archivo que sean const y no extern tienen un enlace externo en C (por defecto para todas las declaraciones de ámbito de archivo), pero un enlace interno en C++.
Ejemplo
#include <stdio.h>
#include <stdlib.h>
/* duración del almacenamiento estático */
int A;
int main(void)
{
printf("&A = %p\n", (void*)&A);
/* duración del almacenamiento automático */
int A = 1; // hides global A
printf("&A = %p\n", (void*)&A);
/* duración del almacenamiento asignado *//
int *ptr_1 = malloc(sizeof(int)); /* inicio de la duración del almacenamiento asignado */
printf("address of int in allocated memory = %p\n", (void*)ptr_1);
free(ptr_1); /* final de la duración del almacenamiento asignado */
}
Posible salida:
&A = 0x600ae4
&A = 0x7ffefb064f5c
address of int in allocated memory = 0x1f28c30
Referencias
- Standard C11 (ISO/IEC 9899:2011):
- 6.2.2 Linkages of identifiers (p: 36-37)
- 6.2.4 Storage durations of objects (p: 38-39)
- 6.7.1 Storage-class specifiers (p: 109-110)
- Standard C99 (ISO/IEC 9899:1999):
- 6.2.2 Linkages of identifiers (p: 30-31)
- 6.2.4 Storage durations of objects (p: 32)
- 6.7.1 Storage-class specifiers (p: 98-99)
- Standard C89/C90 (ISO/IEC 9899:1990):
- 3.1.2.2 Linkages of identifiers
- 3.1.2.4 Storage durations of objects
- 3.5.1 Storage-class specifiers
Véase también
Documentación de C++ para Especificadores para clases de almacenamiento
|