HOWTO · C

La palabra clave register en C

Aprenda cómo funciona el especificador de clase de almacenamiento register en C, incluidas las declaraciones, las restricciones de dirección, los punteros y el ámbito.

En esta página

En las versiones de C que lo admiten, register es un especificador de clase de almacenamiento que tradicionalmente se usaba para sugerir que un objeto podía beneficiarse de un acceso rápido. No garantiza que se almacene en un registro de la CPU ni que el programa sea más rápido. El compilador decide cómo implementar el objeto, y las reglas que se describen a continuación pueden depender del estándar de C al que apunte el compilador.

Descripción general de la palabra clave register en C

El especificador register refleja un modelo de optimización antiguo: los programadores podían marcar los objetos de acceso frecuente como candidatos a almacenarse en registros. Los compiladores modernos toman decisiones de optimización según el programa y la plataforma de destino, así que añadir el especificador no garantiza un mejor rendimiento. Úsalo solo si la versión de C de destino lo admite y las reglas del lenguaje son compatibles con la declaración; si buscas mejorar el rendimiento, mídelo por separado.

Una CPU tiene un número limitado de registros, pero C no exige que los objetos ordinarios se carguen en un registro antes de cada operación. Al traducir y optimizar el programa, el compilador puede mantener los valores en registros, en memoria o en otras ubicaciones. El código fuente no puede depender de una ubicación física concreta. Si el compilador advierte que register está obsoleto o no se admite en el modo de lenguaje seleccionado, consulta la documentación de ese compilador y la versión de C configurada para el proyecto.

Uso de la palabra clave register en C

El siguiente programa completo usa register con tres objetos locales e imprime sus valores. Es un ejemplo ejecutable, pero su salida no se muestra aquí.

#include <stdio.h>

int main(void) {
    register char letter = 'S';
    register double amount = 10.0;
    register int count = 8;

    printf("letter: %c\n", letter);
    printf("amount: %.1f\n", amount);
    printf("count: %d\n", count);
    return 0;
}

La sintaxis de la declaración es familiar: coloca register entre los especificadores de declaración, antes del tipo y del identificador. El ejemplo usa valores fijos para que puedas centrarte en la declaración y en la salida con formato. Que el compilador aplique la sugerencia histórica sobre el almacenamiento depende de la implementación, y la corrección del programa no debe depender de esa decisión.

Cómo obtener la dirección de una variable register en C

En las versiones de C que definen el especificador de clase de almacenamiento register, no se puede aplicar el operador de dirección & a un objeto declarado con register. Esta restricción se aplica incluso si, por casualidad, una implementación mantiene el valor del objeto en memoria. Es una restricción del lenguaje, no una afirmación sobre si un registro físico tiene dirección.

Por ejemplo, la declaración register int item = 22; es válida en un modo de lenguaje compatible, pero int *address = &item; infringe la restricción. El compilador debe diagnosticar una infracción de restricciones, aunque el texto, la gravedad y el formato del diagnóstico dependen de la implementación. No copies el diagnóstico de otro compilador como si la salida estuviera garantizada.

Uso de register con una variable de tipo puntero en C

En las versiones de C que admiten este especificador, un objeto puntero también puede declararse con register. El puntero puede seguir almacenando la dirección de otro objeto; la restricción afecta a obtener la dirección del propio objeto puntero. Por ejemplo, después de int value = 15;, la declaración register int *cursor = &value; permite que cursor apunte a value, y *cursor accede al entero apuntado.

Esta distinción resulta útil al leer código: &value obtiene la dirección del objeto ordinario value, mientras que &cursor intentaría obtener la dirección del objeto puntero declarado con register, algo que la misma restricción no permite. El especificador no cambia a qué apunta un puntero ni garantiza dónde se almacena ninguno de los dos objetos. Si el compilador rechaza la declaración o indica que no admite el especificador, comprueba el modo de lenguaje de destino.

Uso de register con otros especificadores de clase de almacenamiento en C

register es en sí mismo un especificador de clase de almacenamiento, por lo que no se puede combinar con otro especificador de clase de almacenamiento en la misma declaración. En particular, declaraciones como auto register int value;, static register int value; y extern register int value; no son combinaciones válidas en los modos de lenguaje que admiten register.

El compilador diagnostica una combinación no válida, pero el mensaje no está estandarizado como una cadena fija. Para una declaración válida, elige el único especificador de clase de almacenamiento que corresponda a las reglas de duración y enlace deseadas. El tipo (int en estos ejemplos) y los calificadores son partes distintas de una declaración; no hacen compatibles dos especificadores de clase de almacenamiento.

Ámbito de las variables register en C

En las versiones de C que admiten el especificador, este se aplica a objetos con ámbito de bloque y a parámetros de función; no está permitido para objetos con ámbito de archivo. Por ejemplo, un parámetro de función puede declararse como int total(register int count). Dentro del cuerpo de una función, otra forma permitida es una declaración con ámbito de bloque, como register int count = 22;. Una declaración con ámbito de archivo, como register int count;, infringe la restricción aplicable y requiere un diagnóstico.

Por tanto, «variable local» es una descripción incompleta: puede ocultar que los parámetros de función también son un caso permitido. El ámbito y la duración de almacenamiento son conceptos relacionados, pero no equivalentes. El especificador register no promete que un objeto resida en un registro de la CPU, y su presencia no hace que el objeto sea visible fuera de su ámbito habitual. Al mantener código antiguo, comprueba la versión de C y el modo del compilador seleccionados para el proyecto antes de depender de estas declaraciones.