2010-11-11 8 views
5

Muy bien, quiero saber por qué este código está funcionando, me acabo de dar cuenta de que tengo dos variables con el mismo nombre dentro del mismo ámbito.¿Por qué está funcionando este C++? (variables con el mismo nombre)

Estoy usando g ++ (gcc 4.4).

for(int k = 0 ; k < n ; k++) 
    { 
     while(true) 
     { 
      i = Tools::randomInt(0, n); 
      bool exists = false; 

      for(int k = 0 ; k < p_new_solution_size ; k++) 
       if(i == p_new_solution[k]) 
       { 
        exists = true; 
        break; 
       } 
      if(!exists) 
       break; 
     } 

     p_new_solution[p_new_solution_size] = i; 
     p_new_solution_size++; 
    } 
+1

Prueba encender '-Wall', ¿podría quejarte más? –

+1

'Tengo dos variables con el mismo nombre dentro del mismo alcance' ¿Dónde? –

Respuesta

4

Muy bien, quiero saber por qué este código está trabajando, sólo se dio cuenta de que tengo dos variables con el mismo nombre dentro del mismo alcance.

Parece confuso sobre los alcances. No están "dentro del mismo" ámbito ... el k del bucle for tiene su propio alcance anidado/interno. Más importante aún, para ver por qué el lenguaje lo permite, tener en cuenta:

#define DO_SOMETHING \ 
    do { for (int i = 1; i <= 2; ++i) std::cout << i << '\n'; } while (false) 

void f() 
{ 
    for (int i = 1; i <= 10; ++i) 
     DO_SOMETHING(); 
} 

Aquí, el texto sustituido por la macro "hacer_algo" recibe evaluados en el mismo alcance que i. Si está escribiendo DO_SOMETHING, puede necesitar su expansión para almacenar algo en una variable y establecerse en el identificador i; obviamente, no tiene forma de saber si ya existirá en el contexto de la llamada. Podrías tratar de elegir algo más oscuro, pero tendrías personas usando nombres complicados de variables que sufrieran el mantenimiento del código, y sin importar tarde o temprano habría un choque. Por lo tanto, el lenguaje solo permite que los ámbitos internos introduzcan variables con el mismo nombre: la coincidencia más interna se usa hasta que finaliza su alcance.

Incluso cuando no se trata de macros, es una pena tener que detenerse y pensar si algún ámbito externo ya está usando el mismo nombre. Si sabe que solo quiere una operación rápida, puede mostrarla en un alcance independiente (anidado) sin tener en cuenta ese contexto más amplio (siempre que no tenga un código allí que realmente quiera usar la variable de ámbito externo: si lo hace a continuación, puede especificarlo explícitamente (si está delimitado por espacios de nombres y clases, pero si está en un cuerpo de función, necesita cambiar el nombre de su variable de bucle (o crear una referencia o algo similar antes de presentar su nombre propio) variable)).

+0

Ok, lo tengo, quiero decir ... después de todos estos años de C++ y compiladores, nunca pensé en esto. Solo tengo una pequeña pregunta: entonces DO_SOMETHING() tiene un alcance diferente, pero si no sombreara la variable i, podría usar su valor, establecido por el bucle outter ¿no? ¿Qué pasaría si no fuera una macro, en lugar de DO_SOMETHING(), tuvieras obj-> do_this(). Aún cambiaría el alcance, pero ¿qué otra cosa cambiaría ya que este método no puede usar el anterior valor 'i'? Estoy pidiendo esto para saber el nombre de lo que cambia, porque sé cómo funcionan los compiladores ... tuve todo un año sobre ellos, simplemente no sabía que esto funcionó en gcc – hfingler

+0

@polar: Como dices, si DO_SOMETHING no sombreó el externo i podría obtenerlo o configurarlo.Ocasionalmente, eso es intencional: por ejemplo, una forma poderosa de implementar la depuración de calidad empresarial con muchas clasificaciones ortogonales que ayudan a filtrar es teniendo contextos de error en el alcance. En ese modelo, tiene una macro LOG que realmente necesita que haya una variable de contexto de error con un nombre particular en el alcance. Si desea refinar los informes, sombree la versión externa y modifique algunas clasificaciones, proporcione un delta, pero no necesita volver a especificar todo en cada uso de LOG. –

+0

Si DO_SOMETHING era una función en lugar de una macro, no podía acceder a nada desde el ámbito de la persona que llama (no solo la función, sino también los ámbitos de clase/espacio de nombres de los que DO_SOMETHING no es miembro). Todavía puede acceder a los ámbitos en los que está anidado, lo que no es cierto para la macro (las macro no recuerdan en qué espacio de nombres se definieron). –

9

El k en el interior para las sombras de bucle (u oculta) la k en el exterior para el bucle.

Puede declarar múltiples variables con el mismo nombre en diferentes ámbitos. Un ejemplo muy simple sería el siguiente:

int main() 
{ 
    int a;  // 'a' refers to the int until it is shadowed or its block ends 
    { 
     float a; // 'a' refers to the float until the end of this block 
    }   // 'a' now refers to the int again 
} 
+0

¿Debería el compilador emitir una advertencia de que dos variables tienen el mismo nombre en el mismo ámbito? Quiero decir ... podría usar la 'k' externa del bucle interno, por lo que están en el mismo alcance. – hfingler

+0

No se pudo, porque está sombreado. – Crashworks

+0

@ polar: podría dar una advertencia, pero no tiene por qué. Hay muchos casos en que esto podría suceder. Por ejemplo, puede tener una variable en el ámbito del espacio de nombres o puede tener una variable miembro de clase. –

1

Debido a que está permitido tener dos variables del mismo nombre dentro del mismo ámbito, pero no dentro del mismo espacio de declaración. El compilador toma la variable más local del nombre apropiado, similar a cómo puede 'ocultar' las variables globales de nombre X con una variable miembro de nombre X. Sin embargo, debería recibir una advertencia.

+0

Esto no tiene la intención de sonar narky, soy realmente curioso - por mi propio beneficio de aprendizaje ¿alguien puede explicarme qué fue incorrecto en lo anterior que hubiera causado un voto negativo? Aclamaciones. – dlanod

+0

Pensé lo mismo cuando lo vi allí ... ¿por qué alguien menospreció esta respuesta? solo porque es simple pero comprensible? – hfingler

+1

No te he rechazado, pero mereces una explicación y lo adivinaré. Sospecho que es solo una cuestión de terminología. La idea es correcta, pero estás compartiendo o aceptando la idea de que los dos ks estaban en el mismo alcance. No lo eran, estaban en un ámbito interno anidado dentro de un ámbito externo. No estoy seguro de dónde obtuvo su comprensión de los ámbitos frente a los "espacios de declaración", pero nunca antes había oído hablar de espacios de declaración (26 años de programación, la mayoría en C/C++). –

0

En C/C++ del alcance variable está limitado por las apoyos por lo que el siguiente código es válido para el compilador:

int k() 
{ 
    int k; 
    { 
     int k; 
     { 
      int k;    
     }  
    } 
} 
+1

¿Quiere decir * ramas * o * llaves *? – fredoverflow

2

a partir de los documentos estándar, Sec 3.3.1

Cada nombre se introduce en una parte de texto del programa llama una región declarativa, que es el más grande parte del programa en el que ese nombre es válido, es decir, en el que ese nombre se puede utilizar como un nombre no calificado para referirse a la misma entidad .En general, cada nombre particular es válido solo dentro de una parte posiblemente no contigua del texto del programa llamado su alcance. Para determinar el alcance de una declaración, a veces es conveniente referirse al alcance potencial de una declaración. El alcance de una declaración es el mismo como su alcance potencial a menos que el alcance potencial contenga otra declaración del mismo nombre. En ese caso, el alcance potencial de la declaración en la región declarativa interna (contenida) está excluida del alcance de la declaración en la región declarativa (que contiene) externa.

Puede sonar confuso en su primera lectura, pero responde su pregunta.

El alcance potencial es el mismo que el alcance de la declaración a menos que se produzca otra declaración (interna). Si se produjo, el alcance potencial de la declaración externa es eliminado y solo la declaración interna es retenida.

Espero que sea claro y ayuda ..

+0

Has sido claro, pero ese texto toma un tiempo para ser totalmente comprendido. Pero seguro que responde mi pregunta. Gracias. – hfingler

Cuestiones relacionadas