¿Por qué C permite múltiples declaraciones globales de la misma variable pero NO múltiples declaraciones locales?

8

Noté que si declaro una variable global varias veces, el compilador ni siquiera genera una advertencia.

Sin embargo, si declaro una variable local en una función varias veces, por ejemplo, el compilador gcc genera un error y no compila el archivo. (Pregunto en términos de gcc, pero esta es más una pregunta de diseño de lenguaje general, no una pregunta sobre gcc, porque creo que es probable que otros compiladores se comporten de manera similar).

¿Cuál es la explicación de este comportamiento?

yoyo_fun
fuente
Solo para estar seguro, su variable global siempre tuvo el mismo tipo, ¿verdad?
Walfrat
@Walfrat Sí, la variable siempre se declara del mismo tipo. Si dos variables del mismo nombre pero con un tipo diferente se declaran globalmente, el gcc genera el error "tipos conflictivos para una (variable)"
yoyo_fun
3
No puede declarar una variable local ni una sola vez. Todo lo que puedes hacer es definirlo. Declarar una variable es decirle al compilador qué es. Definir una variable es decirle al compilador que le asigne memoria. Debes definir todas las variables. En C, se puede usar una definición de una variable global para una declaración varias veces. Pero si el programa solo tiene extern int x;, que es una declaración, la compilación se cancelará ya que no hay lugar donde se asigne memoria a la variable.
shawnhcorey

Respuestas:

11

De acuerdo con las pautas de codificación :

En el conjunto de unidades de traducción y bibliotecas que constituyen un programa completo, cada declaración de un identificador particular con enlace externo denota el mismo objeto o función. Dentro de una unidad de traducción, cada declaración de un identificador con enlace interno denota el mismo objeto o función. Cada declaración de un identificador sin vinculación denota una entidad única.

La variable local no tiene vinculación. entonces hay un nombre Se produce colisión. Entonces, la declaración múltiple de la variable local no es posible.

La variable global tiene enlace externo. Entonces, es posible la declaración múltiple de variables globales.

msc
fuente
77
Esta respuesta está bien, sin embargo, la pregunta de seguimiento obvia es: ¿cuál es la razón detrás de esta definición?
Doc Brown
Con muchas peculiaridades de C, la razón es que "los compiladores de C pre-estándar lo hicieron de esta manera". Si observa la complejidad de la "definición tentativa", es muy probable que este sea el caso aquí.
Sebastian Redl
9

@msc ofrece una buena introducción a las reglas detrás de este comportamiento.

Noté que si declaro una variable global varias veces, el compilador ni siquiera genera una advertencia.

C tiene tres tipos de declaraciones globales para objetos, a saber, las que están (y estoy pasando por alto staticaquí):

  1. declaraciones que no son definiciones - extern int a;
  2. declaraciones que también son definiciones, int a = 3;oextern int a = 3;
  3. definiciones tentativas int a;

Se permiten múltiples declaraciones de tipo 1 y 3, mientras que a lo sumo se permite una definición (tipo 2).


¿Cuál es la explicación de este comportamiento?

Si también está preguntando sobre la motivación de estas reglas, es un soporte para la compilación por separado . (Ver unidad de traducción ).

Para dividir un programa en múltiples archivos compilados por separado, necesitamos algunas características, a saber (a) poder declarar sin definir necesariamente , y (b) declaración de reenvío .

Dentro de una unidad de traducción necesitamos poder hacer referencia a funciones y datos globales en otra unidad de traducción. Y también nos gustaría realizar algunas comprobaciones de errores, aquí, para descubrir definiciones faltantes y definiciones duplicadas erróneas.

A veces, en la misma unidad de traducción, declaramos un global y luego lo definimos más adelante. Esto puede suceder si necesitamos una declaración directa por alguna razón, o si usamos un archivo de encabezado común (que proporciona declaraciones) dentro de la unidad de traducción que también ofrece definiciones explícitas.

Dado que la compilación separada en C se aplica mediante la vinculación de funciones globales y datos, estas características son necesarias a nivel global pero no a nivel local.

Como señala @msc, nada de esto es necesario para las variables locales, ya que no tienen vinculación.

C (como muchos otros lenguajes) no proporciona enlaces para variables locales, ya que el lenguaje no intenta admitir una sola función que abarque múltiples unidades de traducción separadas.

(Por supuesto, puede hacer que una función abarque varios archivos de origen, pero no múltiples unidades de traducción).

Una definición provisional funciona igual que una declaración, ya que está permitida en múltiples unidades de traducción (y también se combina muy bien con otras declaraciones). Sin embargo, si no hay una definición (no provisional) para el identificador en todo el programa, el conjunto de (una o más) definiciones provisionales en varias unidades de traducción (para un identificador) se toma como una definición para el objeto cuyo inicializador es cero.

Esto se puede implementar al colocarlos en la sección .BSS con el tamaño y la alineación adecuados; el enlazador los emparejará con la definición verdadera si se encuentra, o bien los emparejará entre sí, dándoles espacio cero en BSS.


La noción de compilación separada se puede soportar por completo sin la característica de las definiciones provisionales; creo que las definiciones provisionales existen principalmente por razones históricas. (No digo que no sean útiles, solo si el lenguaje se creó hoy, esto podría verse como innecesario y, por lo tanto, no se ofrecerá).

Erik Eidt
fuente