Sobre variables

26/04/2009 - 21:49 por Esteban | Informe spam
Saludandolos muy afectuosamente a todos

Duda de principiante.

Si tengo un ciclo:

for ()
{
int entero=0;
.

}

En cada iteracion del ciclo for se esta creando una NUEVA variable 'entero'
?
O se reutiliza la misma?

No es mejor asi poner la declaracion antes del for ?

Preguntas similare

Leer las respuestas

#6 Anonimo
28/04/2009 - 17:01 | Informe spam
Hola RFOG.


En C++ es muy habitual hacer cosas así:

//Código
int vi;
//Hacer algo con v1...
{
int contador=fi(v1);
f1(contador);
//etc
}

De este modo contador entra y sale de ámbito y duración entre las llaves,
ahorrando pila.




Muy buen ejemplo para entender mi punto.

Es decir que la llave de cierre 'elimina' la variable local contador (al
menos lógicamente), tal como lo hace un método cuando termina.
Imagino que C# al ser un 'hijo' de C++ debe funcionar igual.

Respecto a lo que comentas de declarar una variable dentro de un bucle y
que se cree en cada iteración, la teoría dice que sí (lo que te ha dicho
Alberto), un compilador de C++ bueno sacará esa variable fuera por
optimización aunque a nivel sintáctico y semántico sería como si estuviera
dentro, lo que hace el C# no tengo ni idea, pero voy a comprobarlo.




Según eso, es de suponer entonces que dejar la variable fuera del bucle debe
ser más eficiente, sobre todo si son varias las variables declaradas dentro
del bucle.

Si llegas a comprobarlo para C# favor me dices. Yo veré también como trato
de hacer algunas pruebas, ya que al venir de otros lenguajes se me dificulta
un poco entender el funcionamiento.


Gracias ;-)
Respuesta Responder a este mensaje
#7 Anonimo
28/04/2009 - 17:05 | Informe spam
Ok, pero si me lo pudieras 'traducir' un poquito ya que no entendí.

Se concluye que ? da lo mismo declararla fuera que dentro del bucle ?




"RFOG" escribió en el mensaje
news:%23$g$
Vaya, el compilador de C# va haciéndose mayor poco a poco.

En este caso:

for(;;)
{
int entero = 0;
for(;entero<10;entero++)
{
Console.WriteLine(entero);
}
}

Es completamente equivalente a declarar entero dentro del ámbito del bucle
for.

En este:

class Program
{
static void cuad(int i)
{
Console.WriteLine(i * i);
}
static void Main(string[] args)
{
for(;;)
{
int entero = 0;
cuad(entero);
for(;entero<10;entero++)
{
Console.WriteLine(entero);
}
}
}
}

Ni siquiera usa la pila, carga 0 en un registro y salta.

Y eso sin pasar por el jitter.

Pasando por el jitter genera un código más que aceptable, borrando el
registro del procesador donde va contador mediante un xor sobre sí mismo,
exactamente a como se haría con un buen optimizador de C++.

De hecho podría haber metido inline cuad, por lo demás, casi perfecto:

00000000 push rbx
00000001 sub rsp,20h
00000005 xor ecx,ecx
00000007 call FFFFFFFFF717BED0
0000000c mov ebx,1
00000011 lea ecx,[rbx-1]
{
Console.WriteLine(entero);
00000014 call FFFFFFFFF717BED0
00000019 mov ecx,ebx
0000001b call FFFFFFFFF717BED0
00000020 add ebx,2
for(;entero<10;entero++)
00000023 cmp ebx,0Bh
00000026 jl 0000000000000011
00000028 jmp 0000000000000005
0000002a add rsp,20h
0000002e pop rbx
0000002f rep ret


"RFOG" wrote in message
news:
El ámbito, duración y visibilidad siguen al de C++ casi a pies juntillas.
Meter un bloque de datos entre llaves es crear un nuevo contexto (para
que te hagas una idea, como si llamaras a una función pero con las
variables externas al bloque visibles).

En C++ es muy habitual hacer cosas así:

//Código
int vi;
//Hacer algo con v1...
{
int contador=fi(v1);
f1(contador);
//etc
}

De este modo contador entra y sale de ámbito y duración entre las llaves,
ahorrando pila.

Respecto a lo que comentas de declarar una variable dentro de un bucle y
que se cree en cada iteración, la teoría dice que sí (lo que te ha dicho
Alberto), un compilador de C++ bueno sacará esa variable fuera por
optimización aunque a nivel sintáctico y semántico sería como si
estuviera dentro, lo que hace el C# no tengo ni idea, pero voy a
comprobarlo.

<e> wrote in message news:
Gracias por responderme.

Cuál es el equivalente a "las llaves" en otros lenguajes ?

Eso quiere decir que las llaves ({}) en C# funcionan parecido a una
rutina interna o una llamada a un metodo aparte o como le llaman ahora
un método anónimo, pero que hereda las variables de su metodo
contenedor?

Mi duda viene porque en otros lenguajes, un bloque Begin..End (lo que
sería mas o menos equivalente a las llaves de C#) no funciona igual que
las llaves en C#.

Ejemplo en T-SQL, esto compila y funciona perfectamente:

DECLARE @I INT=1

WHILE @I<3
BEGIN
declare @ENTERO INT=@I
SET @I=@I+1
END
SELECT @ENTERO --compila bien y me devuelve 2

En cambio, en C# el equivalente no compila:

int I=1;
while (I<3)
{
int ENTERO=I;
I++;
}
MessageBox.Show(ENTERO.ToString()); //<-Da error aqui ya que ENTERO no
existe


Se entiende mi duda ?

gracias


"Alberto Poblacion"
escribió en el mensaje news:
"Esteban" <ee> wrote in message
news:
Saludandolos muy afectuosamente a todos

Duda de principiante.

Si tengo un ciclo:

for ()
{
int entero=0;
.

}

En cada iteracion del ciclo for se esta creando una NUEVA variable
'entero' ?
O se reutiliza la misma?



Depende de como interpretes "nueva" o "reutilizar". La variable va a
ir a parar al Stack, y lo que hace internamente para reservarle sitio
es "mover" el puntero del Stack para hacer un hueco para la variable.
Como el Stack está en el mismo sitio durante todas las iteracíones del
bucle, el "hueco" para la variable va a ir siempre a parar a la misma
posición de memoria. Desde este punto de vista, podrías considerar que
se está reutilizando la variable. En cualquier caso, es irrelevante,
puesto que siempre la inicializas a cero, con lo que se pierde
cualquier valor que tuviera desde la anterior iteración, y en ese
sentido se comporta como si siempre fuera "nueva".

No es mejor asi poner la declaracion antes del for ?



Desde el punto de vista de la mantenibilidad y fiabilidad del
programa, es conveniente declarar cada variable de forma que su alcance
y visibilidad sea los mínimos posibles. En este sentido, es preferible
declarar la variable dentro del bucle en lugar de fuera (suponiendo,
claro está, que su valor no se necesite fuera, y que no tenga que
persistir entre iteraciones del bucle). Desde el punto de vista del
rendimiento te va a dar igual. Aunque la declarases fuera del bucle,
iría igualmente a parar al Stack, y serían igual de costosos los
accesos a la variable.








Microsoft Visual C++ MVP
==>> Mi blog sobre programación: http://geeks.ms/blogs/rfog
Momentos Leves: http://momentosleves.blogspot.com/
Cosas mías: http://rfog.blogsome.com/
Libros, ciencia ficción y desarrollo
>> Los asesores son personas místicas que le piden un numero a una compañía
y luego se lo devuelven.





Microsoft Visual C++ MVP
==> Mi blog sobre programación: http://geeks.ms/blogs/rfog
Momentos Leves: http://momentosleves.blogspot.com/
Cosas mías: http://rfog.blogsome.com/
Libros, ciencia ficción y desarrollo
> Los asesores son personas místicas que le piden un numero a una compañía y
luego se lo devuelven.


Respuesta Responder a este mensaje
#8 RFOG
28/04/2009 - 17:34 | Informe spam
<Esteban> wrote in message news:




Muy buen ejemplo para entender mi punto.

Es decir que la llave de cierre 'elimina' la variable local contador (al
menos lógicamente), tal como lo hace un método cuando termina.
Imagino que C# al ser un 'hijo' de C++ debe funcionar igual.




Sí, eso funciona igual.

Respecto a lo que comentas de declarar una variable dentro de un bucle y
que se cree en cada iteración, la teoría dice que sí (lo que te ha dicho
Alberto), un compilador de C++ bueno sacará esa variable fuera por
optimización aunque a nivel sintáctico y semántico sería como si
estuviera dentro, lo que hace el C# no tengo ni idea, pero voy a
comprobarlo.




Según eso, es de suponer entonces que dejar la variable fuera del bucle
debe ser más eficiente, sobre todo si son varias las variables declaradas
dentro del bucle.




Ya lo he comprobado. En teoría sí que es más eficiente y yo lo recomiendo
así por si acaso, en la práctica a veces puede ser más didáctico o claro a
la hora de ver qué estás haciendo y cómo.

De todos modos esto sólo es válido para tipos integrales. Si tomas un objeto
no trivial el constructor está ahí para reinicializar el objeto, por lo que
sacarlo fuera es mala idea si no tienes alguna forma de resetearlo.

Si llegas a comprobarlo para C# favor me dices. Yo veré también como
trato de hacer algunas pruebas, ya que al venir de otros lenguajes se me
dificulta un poco entender el funcionamiento.




No debes preocuparte hasta ese nivel. Muchas veces todas estas cosas son un
poco académicas y teóricas y no vale la pena echar mucho tiempo en ellas.

Los procesos de optimización en general van por otros lares. Si ese código
se va a ejecutar cinco veces en tu programa da igual lo optimizado que esté,
pero si es algo crítico sí que sería necesario o recomendable intentar
exprimir un poco más el código, no sé si me explico bien.

De todos modos, acabo de probar esto:

class Cosa
{
private int m_numero;
public Cosa()
{
m_numero=0;
}
public int Numero
{
get { return m_numero; }
set { m_numero = value; }
}
}
class Program
{
static void Main(string[] args)
{
for(int hola=0;hola<10;hola++)
{
Cosa entero = new Cosa();
for(;entero.Numero<10;entero.Numero++)
{
Console.WriteLine(entero.Numero);
}
}
}
}

Y sin ser para tirar cohetes, el compilador y el jitter están haciendo buena
labor. De hecho, el código equivalente en C++ (no C++/CLI, sino C++ nativo):

class Cosa
{
int m_numero;
public:
Cosa()
{
m_numero=0;
}
int get_Numero()
{
return m_numero;
}
void set_Numero(int n)
{
m_numero=n;
}
};

int _tmain(int argc, _TCHAR* argv[])
{
for(int hola=0;hola<10;hola++)
{
Cosa *entero = new Cosa();
for(;entero->get_Numero()<10;entero->set_Numero(entero->get_Numero()+1))
{
printf("%i",entero->get_Numero());
}
delete entero;
}
return 0;
}

Genera casi el mismo código en ensamblador que el primero después de ser
pasado por el jitter.


Gracias ;-)







Microsoft Visual C++ MVP
==Mi blog sobre programación: http://geeks.ms/blogs/rfog
Momentos Leves: http://momentosleves.blogspot.com/
Cosas mías: http://rfog.blogsome.com/
Libros, ciencia ficción y desarrollo
Los asesores son personas místicas que le piden un numero a una compañía y
luego se lo devuelven.
Respuesta Responder a este mensaje
#9 RFOG
28/04/2009 - 17:34 | Informe spam
Para lo que nos interesa, sí. :-)

<Esteban> wrote in message news:#c#
Ok, pero si me lo pudieras 'traducir' un poquito ya que no entendí.

Se concluye que ? da lo mismo declararla fuera que dentro del bucle ?




"RFOG" escribió en el mensaje
news:%23$g$
Vaya, el compilador de C# va haciéndose mayor poco a poco.

En este caso:

for(;;)
{
int entero = 0;
for(;entero<10;entero++)
{
Console.WriteLine(entero);
}
}

Es completamente equivalente a declarar entero dentro del ámbito del
bucle for.

En este:

class Program
{
static void cuad(int i)
{
Console.WriteLine(i * i);
}
static void Main(string[] args)
{
for(;;)
{
int entero = 0;
cuad(entero);
for(;entero<10;entero++)
{
Console.WriteLine(entero);
}
}
}
}

Ni siquiera usa la pila, carga 0 en un registro y salta.

Y eso sin pasar por el jitter.

Pasando por el jitter genera un código más que aceptable, borrando el
registro del procesador donde va contador mediante un xor sobre sí mismo,
exactamente a como se haría con un buen optimizador de C++.

De hecho podría haber metido inline cuad, por lo demás, casi perfecto:

00000000 push rbx
00000001 sub rsp,20h
00000005 xor ecx,ecx
00000007 call FFFFFFFFF717BED0
0000000c mov ebx,1
00000011 lea ecx,[rbx-1]
{
Console.WriteLine(entero);
00000014 call FFFFFFFFF717BED0
00000019 mov ecx,ebx
0000001b call FFFFFFFFF717BED0
00000020 add ebx,2
for(;entero<10;entero++)
00000023 cmp ebx,0Bh
00000026 jl 0000000000000011
00000028 jmp 0000000000000005
0000002a add rsp,20h
0000002e pop rbx
0000002f rep ret


"RFOG" wrote in message
news:
El ámbito, duración y visibilidad siguen al de C++ casi a pies
juntillas. Meter un bloque de datos entre llaves es crear un nuevo
contexto (para que te hagas una idea, como si llamaras a una función
pero con las variables externas al bloque visibles).

En C++ es muy habitual hacer cosas así:

//Código
int vi;
//Hacer algo con v1...
{
int contador=fi(v1);
f1(contador);
//etc
}

De este modo contador entra y sale de ámbito y duración entre las
llaves, ahorrando pila.

Respecto a lo que comentas de declarar una variable dentro de un bucle y
que se cree en cada iteración, la teoría dice que sí (lo que te ha dicho
Alberto), un compilador de C++ bueno sacará esa variable fuera por
optimización aunque a nivel sintáctico y semántico sería como si
estuviera dentro, lo que hace el C# no tengo ni idea, pero voy a
comprobarlo.

<e> wrote in message news:
Gracias por responderme.

Cuál es el equivalente a "las llaves" en otros lenguajes ?

Eso quiere decir que las llaves ({}) en C# funcionan parecido a una
rutina interna o una llamada a un metodo aparte o como le llaman ahora
un método anónimo, pero que hereda las variables de su metodo
contenedor?

Mi duda viene porque en otros lenguajes, un bloque Begin..End (lo que
sería mas o menos equivalente a las llaves de C#) no funciona igual que
las llaves en C#.

Ejemplo en T-SQL, esto compila y funciona perfectamente:

DECLARE @I INT=1

WHILE @I<3
BEGIN
declare @ENTERO INT=@I
SET @I=@I+1
END
SELECT @ENTERO --compila bien y me devuelve 2

En cambio, en C# el equivalente no compila:

int I=1;
while (I<3)
{
int ENTERO=I;
I++;
}
MessageBox.Show(ENTERO.ToString()); //<-Da error aqui ya que ENTERO no
existe


Se entiende mi duda ?

gracias


"Alberto Poblacion"
escribió en el mensaje news:
"Esteban" <ee> wrote in message
news:
Saludandolos muy afectuosamente a todos

Duda de principiante.

Si tengo un ciclo:

for ()
{
int entero=0;
.

}

En cada iteracion del ciclo for se esta creando una NUEVA variable
'entero' ?
O se reutiliza la misma?



Depende de como interpretes "nueva" o "reutilizar". La variable va
a ir a parar al Stack, y lo que hace internamente para reservarle
sitio es "mover" el puntero del Stack para hacer un hueco para la
variable. Como el Stack está en el mismo sitio durante todas las
iteracíones del bucle, el "hueco" para la variable va a ir siempre a
parar a la misma posición de memoria. Desde este punto de vista,
podrías considerar que se está reutilizando la variable. En cualquier
caso, es irrelevante, puesto que siempre la inicializas a cero, con lo
que se pierde cualquier valor que tuviera desde la anterior iteración,
y en ese sentido se comporta como si siempre fuera "nueva".

No es mejor asi poner la declaracion antes del for ?



Desde el punto de vista de la mantenibilidad y fiabilidad del
programa, es conveniente declarar cada variable de forma que su
alcance y visibilidad sea los mínimos posibles. En este sentido, es
preferible declarar la variable dentro del bucle en lugar de fuera
(suponiendo, claro está, que su valor no se necesite fuera, y que no
tenga que persistir entre iteraciones del bucle). Desde el punto de
vista del rendimiento te va a dar igual. Aunque la declarases fuera
del bucle, iría igualmente a parar al Stack, y serían igual de
costosos los accesos a la variable.








Microsoft Visual C++ MVP
==>>> Mi blog sobre programación: http://geeks.ms/blogs/rfog
Momentos Leves: http://momentosleves.blogspot.com/
Cosas mías: http://rfog.blogsome.com/
Libros, ciencia ficción y desarrollo
>>> Los asesores son personas místicas que le piden un numero a una compañía
y luego se lo devuelven.





Microsoft Visual C++ MVP
==>> Mi blog sobre programación: http://geeks.ms/blogs/rfog
Momentos Leves: http://momentosleves.blogspot.com/
Cosas mías: http://rfog.blogsome.com/
Libros, ciencia ficción y desarrollo
>> Los asesores son personas místicas que le piden un numero a una compañía
y luego se lo devuelven.









Microsoft Visual C++ MVP
==Mi blog sobre programación: http://geeks.ms/blogs/rfog
Momentos Leves: http://momentosleves.blogspot.com/
Cosas mías: http://rfog.blogsome.com/
Libros, ciencia ficción y desarrollo
Los asesores son personas místicas que le piden un numero a una compañía y
luego se lo devuelven.
Respuesta Responder a este mensaje
#10 Anonimo
28/04/2009 - 18:00 | Informe spam
Bien. Muchísimas gracias !


"RFOG" escribió en el mensaje
news:

<Esteban> wrote in message news:




Muy buen ejemplo para entender mi punto.

Es decir que la llave de cierre 'elimina' la variable local contador (al
menos lógicamente), tal como lo hace un método cuando termina.
Imagino que C# al ser un 'hijo' de C++ debe funcionar igual.




Sí, eso funciona igual.

Respecto a lo que comentas de declarar una variable dentro de un bucle y
que se cree en cada iteración, la teoría dice que sí (lo que te ha dicho
Alberto), un compilador de C++ bueno sacará esa variable fuera por
optimización aunque a nivel sintáctico y semántico sería como si
estuviera dentro, lo que hace el C# no tengo ni idea, pero voy a
comprobarlo.




Según eso, es de suponer entonces que dejar la variable fuera del bucle
debe ser más eficiente, sobre todo si son varias las variables declaradas
dentro del bucle.




Ya lo he comprobado. En teoría sí que es más eficiente y yo lo recomiendo
así por si acaso, en la práctica a veces puede ser más didáctico o claro a
la hora de ver qué estás haciendo y cómo.

De todos modos esto sólo es válido para tipos integrales. Si tomas un
objeto no trivial el constructor está ahí para reinicializar el objeto,
por lo que sacarlo fuera es mala idea si no tienes alguna forma de
resetearlo.

Si llegas a comprobarlo para C# favor me dices. Yo veré también como
trato de hacer algunas pruebas, ya que al venir de otros lenguajes se me
dificulta un poco entender el funcionamiento.




No debes preocuparte hasta ese nivel. Muchas veces todas estas cosas son
un poco académicas y teóricas y no vale la pena echar mucho tiempo en
ellas.

Los procesos de optimización en general van por otros lares. Si ese código
se va a ejecutar cinco veces en tu programa da igual lo optimizado que
esté, pero si es algo crítico sí que sería necesario o recomendable
intentar exprimir un poco más el código, no sé si me explico bien.

De todos modos, acabo de probar esto:

class Cosa
{
private int m_numero;
public Cosa()
{
m_numero=0;
}
public int Numero
{
get { return m_numero; }
set { m_numero = value; }
}
}
class Program
{
static void Main(string[] args)
{
for(int hola=0;hola<10;hola++)
{
Cosa entero = new Cosa();
for(;entero.Numero<10;entero.Numero++)
{
Console.WriteLine(entero.Numero);
}
}
}
}

Y sin ser para tirar cohetes, el compilador y el jitter están haciendo
buena labor. De hecho, el código equivalente en C++ (no C++/CLI, sino C++
nativo):

class Cosa
{
int m_numero;
public:
Cosa()
{
m_numero=0;
}
int get_Numero()
{
return m_numero;
}
void set_Numero(int n)
{
m_numero=n;
}
};

int _tmain(int argc, _TCHAR* argv[])
{
for(int hola=0;hola<10;hola++)
{
Cosa *entero = new Cosa();
for(;entero->get_Numero()<10;entero->set_Numero(entero->get_Numero()+1))
{
printf("%i",entero->get_Numero());
}
delete entero;
}
return 0;
}

Genera casi el mismo código en ensamblador que el primero después de ser
pasado por el jitter.


Gracias ;-)







Microsoft Visual C++ MVP
==> Mi blog sobre programación: http://geeks.ms/blogs/rfog
Momentos Leves: http://momentosleves.blogspot.com/
Cosas mías: http://rfog.blogsome.com/
Libros, ciencia ficción y desarrollo
> Los asesores son personas místicas que le piden un numero a una compañía y
luego se lo devuelven.


Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaSiguiente AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida