Las declaraciones de variables en los archivos de encabezado - estática o no?

StackOverflow https://stackoverflow.com/questions/92546

  •  01-07-2019
  •  | 
  •  

Pregunta

Cuando la refactorización de algunos #defines Me encontré con declaraciones similares a los siguientes en C++ archivo de encabezado:

static const unsigned int VAL = 42;
const unsigned int ANOTHER_VAL = 37;

La pregunta es, ¿qué diferencia, si alguna, la estática de hacer?Tenga en cuenta que varios de inclusión de los encabezados no es posible debido a la clásica #ifndef HEADER #define HEADER #endif truco (si lo que importa).

¿La estática significar sólo una copia de VAL se crea, en caso de que el encabezado se incluye por más de un archivo de origen?

¿Fue útil?

Solución

El static significa que habrá una copia de VAL creado para cada archivo de código fuente se incluye en.Pero también significa que múltiples inclusiones no dar lugar a múltiples definiciones de VAL que se chocan en el momento de enlazar.En C, sin la static usted necesita para asegurarse de que sólo un archivo de origen definido VAL mientras que los otros archivos de origen declaró extern.Generalmente se hace por definir (posiblemente con un inicializador) en un archivo de código fuente y poner la extern declaración en un archivo de encabezado.

static variables a nivel mundial son sólo visibles en su propio archivo de origen si llegaron allí a través de una inclusión o estaban en el archivo principal.


Nota del Editor: En C++, const los objetos con que ni el static ni extern palabras clave en su declaración implícitamente static.

Otros consejos

El static y extern etiquetas en el archivo ámbito de las variables de determinar si son accesibles en otras unidades de traducción (es decir,otros .c o .cpp los archivos).

  • static le da a la variable de vinculación interna, escondiendo de otras unidades de traducción.Sin embargo, las variables con vinculación interna puede ser definido de varias unidades de traducción.

  • extern le da a la variable de vinculación externa, lo que es visible a otras unidades de traducción.Normalmente, esto significa que la variable debe ser definido en una unidad de traducción.

El valor por defecto (cuando no se especifica static o extern es uno de los ámbitos en los que C y C++ son diferentes.

  • En C, archivo ámbito de las variables se extern (vinculación externa) de forma predeterminada.Si estás usando C, VAL es static y ANOTHER_VAL es extern.

  • En C++, archivo ámbito de las variables se static (vinculación interna) por defecto, si son const, y extern por defecto, si no lo son.Si estás usando C++, tanto VAL y ANOTHER_VAL son static.

A partir de un proyecto de la C la especificación:

6.2.2 los Vínculos de los identificadores ...-5 - Si la declaración de un identificador para una función que no tiene ninguna clase de almacenamiento especificador, su vinculación se determina exactamente como si fuera declarado con la clase de almacenamiento especificador extern.Si la declaración de un identificador de un objeto ha ámbito de los archivos y no de clase de almacenamiento especificador, su enlace es externo.

A partir de un proyecto de la C++ especificación:

7.1.1 - especificadores de clase de Almacenamiento [dcl.stc] ...-6 - Un nombre declarado en un ámbito de espacio de nombres sin una clase de almacenamiento-especificador tiene vinculación externa a menos que haya vinculación interna debido a una declaración anterior y siempre que no sea declarado const.Los objetos declarados const y no explícitamente declarado extern tienen vinculación interna.

La estática significa que usted obtenga una copia de cada archivo, pero a diferencia de otros han dicho que es perfectamente legal para hacerlo.Usted puede fácilmente probar esto con un pequeño código de ejemplo:

prueba.h:

static int TEST = 0;
void test();

test1.cpp:

#include <iostream>
#include "test.h"

int main(void) {
    std::cout << &TEST << std::endl;
    test();
}

test2.cpp:

#include <iostream>
#include "test.h"

void test() {
    std::cout << &TEST << std::endl;
}

Ejecuta esto le da este resultado:

0x446020
0x446040

const las variables en C++ tienen vinculación interna.Así, el uso de static no tiene ningún efecto.

una.h

const int i = 10;

one.cpp

#include "a.h"

func()
{
   cout << i;
}

two.cpp

#include "a.h"

func1()
{
   cout << i;
}

Si esto fuera un programa en C, se obtendrá múltiples definición de' error para i (debido a la vinculación externa).

La estática de la declaración en este nivel de código significa que el variabel sólo es visible en la actual unidad de compilación.Esto significa que sólo el código dentro del módulo que se va a ver esa variable.

si usted tiene un archivo de encabezado que se declara una variable estática y que el encabezado se incluye en varios C/archivos CPP, luego de que la variable será "local" a estos módulos.Habrá N copias de esa variable para el N lugares que el encabezado se incluye.No están relacionados el uno al otro en absoluto.Cualquier código dentro de cualquiera de los archivos de origen sólo hacer referencia a la variable que se declara dentro de ese módulo.

En este caso particular, la "estática" de la palabra clave parece ser que no proporciona ningún beneficio.Yo puede ser que falte algo, pero parece que no importa-nunca he visto nada como esto antes.

Como para alineaciones, en este caso la variable es probable que entre líneas, pero eso es sólo porque es declarado const.El compilador podría ser más probable en línea módulo de variables estáticas, sino que depende de la situación y el código que se compila.No hay ninguna garantía de que el compilador en línea 'estática'.

El libro de lenguaje C (línea gratis) tiene un capítulo acerca de la vinculación, la cual se explica el significado de 'estática' en más detalle (aunque la respuesta correcta es que ya se da en otros comentarios):http://publications.gbdirect.co.uk/c_book/chapter4/linkage.html

Para responder a la pregunta, "¿la estática significar sólo una copia de VAL se crea, en caso de que el encabezado se incluye por más de un archivo de origen?"...

NO.VAL siempre va a ser definido por separado en cada archivo que incluye el encabezado.

Las normas para C y C++ no causa una diferencia en este caso.

En C, archivo ámbito de variables extern por defecto.Si estás usando C, VAL es estático y ANOTHER_VAL es extern.

Tenga en cuenta que la Moderna enlazadores pueden quejarse de ANOTHER_VAL si el encabezado se incluye en diferentes archivos (mismo nombre global definen dos veces), y sin duda se quejan si ANOTHER_VAL fue inicializado a un valor diferente en otro archivo

En C++, archivo ámbito de las variables son estáticas por defecto si se const, y extern por defecto, si no lo son.Si estás usando C++, tanto VAL y ANOTHER_VAL son estáticos.

También es necesario tomar en cuenta el hecho de que ambas variables son designados const.Lo ideal es que el compilador siempre elegir en línea de estas variables y no incluyen ningún tipo de almacenamiento para ellos.Hay un montón de razones por las que el almacenamiento puede ser asignado.Queridos puedo pensar...

  • opciones de depuración
  • dirección tomada en el archivo
  • compilador siempre asigna almacenamiento (const complejo tipos no pueden ser fácilmente insertados, por lo que se convierte en un caso especial para los tipos básicos)

Usted no puede declarar una variable estática sin definir así (esto es debido a que la clase de almacenamiento modificadores static y extern son mutuamente excluyentes).Una variable estática puede ser definido en un archivo de encabezado, pero esto haría que cada archivo de código fuente que incluye el archivo de cabecera para tener su propia copia privada de la variable, que es, probablemente, no era mi intención.

Suponiendo que estas declaraciones son en el ámbito global (es decir,no son variables miembro), entonces:

estática significa 'vinculación interna'.En este caso, ya que se declara const este puede ser optimizado/insertados por el compilador.Si se omite el const a continuación, el compilador debe asignar el almacenamiento en cada unidad de compilación.

Por la omisión de estática la vinculación es extern de forma predeterminada.De nuevo, se ha salvado por la constness - el compilador puede optimizar/en línea de uso.Si se le cae la const a continuación, aparecerá una multiplicar símbolos definidos error en tiempo de vínculo.

const las variables son por defecto estática en C++, pero extern C.Así que si usas C++ esto no tiene sentido lo de la construcción a utilizar.

(7.11.6 C++ 2003, y Apexndix C ha de muestras)

Ejemplo en comparar de compilación y enlace de las fuentes de C y C++ programa:

bruziuz:~/test$ cat a.c
const int b = 22;
int main(){return 0;}
bruziuz:~/test$ cat b.c
const int b=2;
bruziuz:~/test$ gcc -x c -std=c89 a.c b.c
/tmp/ccSKKIRZ.o:(.rodata+0x0): multiple definition of `b'
/tmp/ccDSd0V3.o:(.rodata+0x0): first defined here
collect2: error: ld returned 1 exit status
bruziuz:~/test$ gcc -x c++ -std=c++03 a.c b.c 
bruziuz:~/test$ 
bruziuz:~/test$ gcc --version | head -n1
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609

Estática evita que otra unidad de compilación de externing esa variable para que el compilador sólo puede "inline" el valor de la variable de donde se usa y no crear la memoria de almacenamiento para él.

En el segundo ejemplo, el compilador no puede asumir que algún otro archivo de origen no extern, por lo que en realidad debe almacenar el valor en la memoria en algún lugar.

Estática impide que el compilador a partir de la adición de varias instancias.Esto se hace menos importante con #ifndef protección, pero suponiendo que el encabezado se incluye en dos separadas de las bibliotecas, y la aplicación está vinculada, dos instancias que sería incluido.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top