Unidades de traducción y vinculación

En un programa de C++, un símbolo, por ejemplo, una variable o un nombre de función, se puede declarar cualquier número de veces dentro de su ámbito. Sin embargo, solo puede definirse una vez. Esta regla es la "Regla de definición única" (ODR). Una declaración introduce (o reintroduce) un nombre en el programa junto con suficiente información para asociar posteriormente el nombre a una definición. Una definición introduce un nombre y proporciona toda la información necesaria para crearlo. Si el nombre representa una variable, una definición crea explícitamente el almacenamiento y lo inicializa. Una definición de función consta de la firma más el cuerpo de la función. Una definición de clase consta del nombre de clase seguido de un bloque que enumera todos los miembros de la clase. (Los cuerpos de las funciones miembro se pueden definir opcionalmente por separado en otro archivo).

En el siguiente ejemplo se muestran algunas declaraciones:

int i;
int f(int x);
class C;

En el siguiente ejemplo se muestran algunas definiciones:

int i{42};
int f(int x){ return x * i; }
class C {
public:
   void DoSomething();
};

Un programa consta de una o más unidades de traducción. Una unidad de traducción consta de un archivo de implementación y de todos los encabezados que incluye directa o indirectamente. Normalmente, los archivos de implementación tienen una extensión de archivo de .cpp o .cxx. Normalmente, los archivos de encabezado tienen una extensión de .h o .hpp. Cada unidad de traducción es compilada independientemente por el compilador. Una vez completada la compilación, el enlazador combina las unidades de traducción compiladas en un único programa. Las infracciones de la regla de ODR suelen aparecer como errores del vinculador. Los errores del enlazador se producen cuando el mismo nombre se define en más de una unidad de traducción.

En general, la mejor manera de hacer que una variable sea visible en varios archivos es declararla en un archivo de encabezado. A continuación, agregue una directiva #include en cada archivo .cpp que requiera la declaración. Al agregar protección de inclusión alrededor del contenido del encabezado, asegúrese de que los nombres que declara un encabezado solo se declaran una vez para cada unidad de traducción. Defina el nombre en un solo archivo de implementación.

En C++20, los módulos se presentan como una alternativa mejorada para los archivos de encabezado.

En algunos casos, puede ser necesario declarar una variable global o una clase en un archivo .cpp. En esos casos, se necesita una manera de indicar al compilador y al enlazador qué tipo de vinculación tiene el nombre. El tipo de vinculación especifica si el nombre del objeto solo está visible en un archivo o en todos los archivos. El concepto de vinculación solo se aplica a los nombres globales. El concepto de vinculación no se aplica a los nombres que se declaran dentro de un ámbito. Un ámbito se especifica mediante un conjunto de llaves que lo encierran, como en las definiciones de función o clase.

Vinculación externa frente a interna

Una función libre es una función que se define en el ámbito global o del espacio de nombres. De forma predeterminada, las variables globales no-const y las funciones libres tienen vinculación externa; son visibles desde cualquier unidad de traducción del programa. Ningún otro objeto global puede tener ese nombre. Un símbolo con vinculación interna o ninguna vinculación solo está visible dentro de la unidad de traducción en la que se declara. Cuando un nombre tiene vinculación interna, el mismo nombre puede existir en otra unidad de traducción. Las variables declaradas dentro de las definiciones de clase o los cuerpos de función no tienen vinculación.

Puede forzar que un nombre global tenga vinculación interna declarándolo explícitamente como static. Esta palabra clave limita su visibilidad a la misma unidad de traducción en la que se declara. En este contexto, static significa algo diferente que cuando se aplica a variables locales.

Los objetos siguientes tienen vinculación interna de forma predeterminada:

  • Objetos const.
  • Objetos constexpr.
  • Objetos typedef.
  • Objetos static en el ámbito del espacio de nombres

Para proporcionar una vinculación externa de objeto const, declárela como extern y asígnele un valor:

extern const int value = 42;

Para obtener más información, vea extern.

Consulte también

Conceptos básicos