2010-08-21 13 views
6

Tengo algunas preguntas sobre el enlace de las siguientes variables. Por ejemplos de 7.1.1/7 de C++ 03 y experimentando con los compiladores (Comeau, Clang y GCC), llegué a los siguientes tipos de enlace:Vinculación de varias variables estáticas/estáticas

  1. Primera static, entonces extern

    static int a; // (a) 
    extern int a; // (b) valid, 'a' still internal 
    

    Es claro para mí de acuerdo con la sección 3.5: (a) implica vinculación interna. Y (b) también implica vinculación interna, porque el nombre "a" se declara estático (por (a)).

  2. Primera extern, entonces static

    extern int b; // (c) 
    static int b; // (d) invalid! 
    

    En primer lugar, (c) implica la vinculación externa. Pero (d) implica una vinculación interna porque el nombre "b" se declara estático por (d). Esto no es válido de acuerdo con 7.1.1/7, ya que la vinculación implícita no es consistente.

  3. Primera const, entonces extern

    const double pi1 = 3.14; // (e) 
    extern const double pi1; // (f) valid and 'pi1' is internal 
    

    En primer lugar, (e) implica enlace interno, porque es constante, y tampoco lo declarado extern explícita ni implícita vinculación externa con anterioridad. Y (f) debería implicar un enlace externo y ser un error, porque explícitamente declara el nombre extern, ¡pero los compiladores lo mantienen interno! ¿Por qué?Esa es mi pregunta.

  4. Primera extern, entonces const

    extern const double pi2; // (g) 
    const double pi2 = 3.14; // (h) valid and 'pi2' is external 
    

    Ahora, (g) implica la vinculación externa porque declaramos explícitamente extern. Y (h) también implica un enlace externo porque (g) explícitamente declarado extern.


he encontrado experimentalmente a cabo la unión de 3 y 4 con la plantilla siguiente (se requiere que el segundo argumento de tener enlazado externo)

template<typename T, T&> struct ensure { }; 

ensure<const double, pi1> e1; // failed 
ensure<const double, pi2> e2; // succeeded 

Resumen: La Discusión con Charles Bailey resultó ser bastante fructífera y mostró que hay dos posibles interpretaciones de 3.5/3, donde la importancia nt punto de viñeta dice

Un nombre que tiene un ámbito de espacio de nombres (3.3.5) tiene enlace interno si es el nombre de

  • un objeto o de referencia que se declara explícitamente const y extern ni declarado explícitamente ni declarado previamente tener vinculación externa;

Si nos fijamos en el punto (f), a continuación, las dos interpretaciones llegan a conclusiones diferentes, como se muestra a continuación

  1. La primera interpretación señala que se declara pi1const sino que también se declara extern. La variable tiene así external vinculación.

  2. La segunda interpretación interpreta ambas ocurrencias de "declarado" para hacer referencia a la misma declaración. De esta forma, significa que está declarado const, pero no extern const. Observamos que (e) se declara const y no extern const, por lo que damos pi1 enlace interno.

¿Qué interpretación es correcta? No puedo determinar a partir de esa redacción, pero los compiladores parecen interpretar esto de la segunda manera. En particular, si tomamos la primera interpretación, entonces la última parte citada de 3.5/3 sería superflua, porque no habría un escenario válido en el que un nombre se declararía const y se declararía previamente con un enlace externo pero sin un extern explícito.

+1

Tal vez me falta algo, ¿pero 3 no es lo mismo que 1? (Es decir, ¿el nombre 'pi1' está 'declarado estático' por así decirlo?). Aunque supongo que solo le pregunté por qué 4 no es inválido. – GManNickG

+0

@GMan, consulte 3.5/3 para estos dos casos. Se manejan por diferentes puntos de viñeta. –

+0

@GMan para 4, el primero lo hizo externo y el segundo no lo convierte en interno, porque el nombre fue declarado explícitamente externo (por la primera declaración). Entonces, solo el primero, así como el primero y el segundo juntos implican el mismo vínculo. Para 2, solo el primero implica un enlace externo, pero el primero y el segundo juntos implican un enlace interno porque el nombre se declara explícitamente estático por el segundo. Por lo tanto, no es válido. –

Respuesta

4
const double pi1 = 3.14; // (e) 
extern const double pi1; // (f) valid and 'pi1' is internal 

Mi interpretación es la siguiente. Al considerar la vinculación de un nombre, consideramos las declaraciones anteriores, así como la que se interpreta en este momento en el análisis. Es por eso que static int a; extern int a; está bien, pero extern int b; static int b; no.

Al encontrar la primera declaración notamos que pi1 se declara explícitamente const pero no se declaró explícitamente extern ni se declaró previamente que tenía un enlace externo. Esto coincide con una de las opciones de 3.5/2, por lo tanto, pi1 tiene un enlace interno.

Al encontrar la segunda declaración que preguntamos es pi1 el nombre de un objeto que se declara explícitamente const pero ni explícitamente declaró extern ni [... blah ...]. Sostengo que es porque así fue declarado en el punto (e).Claro, no está declarado de esa manera en todas partes, pero de la misma manera a era el nombre de un objeto declarado static cuando estábamos considerando la declaración extern int a; a pesar de que no fue declarada static en todas partes. Esto, para mí, significa que la declaración (f) no implica un vínculo diferente de la declaración (e).

+0

Creo que su interpretación tiene sentido. Creo que ahora lo que dice el Estándar es que se declara explícitamente como const, pero no como "const externo". Porque de lo contrario, el texto posterior "ni previamente declarado tener un enlace externo"; Sería superfluo: la declaración que usa "const" pero no "extern" será una definición, pero para estar bien formada, cualquier otra declaración * tendrá * que usar 'extern'. Solo en la interpretación de "contern externo", que usted aplica, creo, el texto adicional no es superfluo. –

+0

He cambiado mi pregunta para resumir nuestros hallazgos, y voy a aceptar esta. –

0

Creo que en el n. ° 3 ha cometido un error en su análisis. Por lo que sé, const no implica nada sobre el enlace. No estoy seguro de cómo se llega a la conclusión de que el compilador hace que el enlace sea interno. La mayoría de los compiladores (como una optimización) reemplazarán todas las referencias a la variable const por el valor en el que se inicializaron, por lo que el símbolo puede no aparecer en absoluto en el código.

E incluso si no lo hizo, está claro desde el n. ° 1 que si algo con enlace interno se declara posteriormente con la palabra clave extern que permanece con el enlace interno. Así que no sé por qué esperarías un error.

Y si const implica vinculación interna, entonces # 4 debe ser un error por la misma razón # 2 es.

+2

'const' implica vínculo interno. 7.1.1/6: "Un nombre declarado en un ámbito de espacio de nombres sin _storage-class-specifier_ tiene un enlace externo a menos que tenga un enlace interno debido a una declaración previa y siempre que no se haya declarado' const'. Los objetos declarados 'const' y no explícitamente declarado 'extern' tiene un enlace interno. " –

0

Tener ambos (e) y (f) en el mismo ámbito de espacio de nombres simplemente no es válido, según §7.1.1/7 "Los enlaces implicados por las declaraciones sucesivas para una entidad determinada deberán estar de acuerdo.".

Esta regla requiere un diagnóstico.

Sin embargo, al menos Comeau Online no diagnostica la infracción.

Saludos & HTH,

EDIT:. Él él, miré hacia arriba DR 426, como se menciona en otra respuesta aquí, y parece que los redactores de la propuesta de acuerdo, por lo que es UB en lugar de diagnosticable, eran no consciente de §7.1.1/7. No voy a comentar sobre el tema ni siquiera a plantearlo en comp.std.C++ porque considero que el trabajo de estandarización es demasiado político y sin sentido (argumentos extravagantes) para mí. Pero de cualquier manera, el código no es válido.

+0

¿Qué quiere decir con "argumentos extravagantes"? –

+0

@Johannes: p. el argumento de que, por consistencia, un ciclo infinito de no hacer nada debería ser UB. O el argumento de que las operaciones de movimiento deberían poder lanzar (no recuerdo cuál fue ese argumento). Pronto. Aclamaciones, –

Cuestiones relacionadas