Namespaces
Variants

External and tentative definitions

From cppreference.net

En el nivel superior de una unidad de traducción (es decir, un archivo fuente con todos los #includes después del preprocesador), cada programa C es una secuencia de declaraciones , que declaran funciones y objetos con enlace externo o interno . Estas declaraciones se conocen como declaraciones externas porque aparecen fuera de cualquier función.

extern int n; // declaración externa con enlace externo
int b = 1;    // definición externa con enlace externo
static const char *c = "abc"; // definición externa con enlace interno
int f(void)    // definición externa con enlace externo
{
    int a = 1; // no externa
    return b;
}
static void x(void) // definición externa con enlace interno
{
}

Los objetos declarados con una declaración externa tienen duración de almacenamiento estática , y como tales no pueden usar los especificadores auto o register excepto que auto puede usarse para inferencia de tipos (desde C23) . Los identificadores introducidos por declaraciones externas tienen ámbito de archivo .

Contenidos

Definiciones tentativas

Una definición tentativa es una declaración externa sin un inicializador, y sin un especificador de clase de almacenamiento o con el especificador static .

Una definición tentativa es una declaración que puede o no actuar como una definición. Si se encuentra una definición externa real anterior o posteriormente en la misma unidad de traducción, entonces la definición tentativa simplemente actúa como una declaración.

int i1 = 1;     // definición, enlace externo
int i1;         // definición tentativa, actúa como declaración porque i1 está definido
extern int i1;  // declaración, se refiere a la definición anterior
extern int i2 = 3; // definición, enlace externo
int i2;            // definición tentativa, actúa como declaración porque i2 está definido
extern int i2;     // declaración, se refiere a la definición de enlace externo

Si no hay definiciones en la misma unidad de traducción, entonces la definición tentativa actúa como una definición real que empty-initializes el objeto.

int i3;        // definición tentativa, enlace externo
int i3;        // definición tentativa, enlace externo
extern int i3; // declaración, enlace externo
// en esta unidad de traducción, i3 se define como si fuera "int i3 = 0;"

A diferencia de las declaraciones extern , que no cambian la vinculación de un identificador si una declaración previa la estableció, las definiciones tentativas pueden discrepar en vinculación con otra declaración del mismo identificador. Si dos declaraciones para el mismo identificador están en alcance y tienen diferente vinculación, el comportamiento es indefinido:

static int i4 = 2; // definición, enlace interno
int i4;            // Comportamiento indefinido: desacuerdo de enlace con la línea anterior
extern int i4;     // declaración, se refiere a la definición de enlace interno
static int i5; // definición tentativa, enlace interno
int i5;        // Comportamiento indefinido: desacuerdo de enlace con la línea anterior
extern int i5; // se refiere al anterior, cuyo enlace es interno

Una definición tentativa con enlace interno debe tener tipo completo.

static int i[]; // Error, tipo incompleto en una definición tentativa estática
int i[]; // OK, equivalente a int i[1] = {0}; a menos que se redeclare más adelante en este archivo

Regla de una definición

Cada unidad de traducción puede tener cero o una definición externa de cada identificador con enlace interno (un global static ).

Si un identificador con enlace interno se utiliza en cualquier expresión que no sea no-VLA, (desde C99) sizeof , _Alignof (desde C11) (hasta C23) , alignof (desde C23) , o typeof (desde C23) , debe haber una y solo una definición externa para ese identificador en la unidad de traducción.

El programa completo puede tener cero o una definición externa de cada identificador con enlace externo .

Si un identificador con enlace externo se utiliza en cualquier expresión que no sea no-VLA, (desde C99) sizeof , _Alignof (desde C11) (hasta C23) , alignof (desde C23) , o typeof (desde C23) , debe existir una y solo una definición externa para ese identificador en algún lugar del programa completo.

Notas

Las definiciones inline en diferentes unidades de traducción no están restringidas por la regla de una definición. Consulte inline para los detalles sobre las definiciones de funciones inline.

(desde C99)

Consulte duración de almacenamiento y enlace para el significado de la palabra clave extern con declaraciones en el ámbito de archivo

Consulte definiciones para la distinción entre declaraciones y definiciones.

Las definiciones tentativas se inventaron para estandarizar varios enfoques pre-C89 de declarar anticipadamente identificadores con enlace interno.

Referencias

  • Estándar C23 (ISO/IEC 9899:2024):
  • 6.9 Definiciones externas (p: TBD)
  • Estándar C17 (ISO/IEC 9899:2018):
  • 6.9 Definiciones externas (p: 113-116)
  • Estándar C11 (ISO/IEC 9899:2011):
  • 6.9 Definiciones externas (p: 155-159)
  • Estándar C99 (ISO/IEC 9899:1999):
  • 6.9 Definiciones externas (p: 140-144)
  • Estándar C89/C90 (ISO/IEC 9899:1990):
  • 3.7 DEFINICIONES EXTERNAS