Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: 7emiliosk8 en 5 Febrero 2017, 04:28 am



Título: otra manera de escribir *envp++
Publicado por: 7emiliosk8 en 5 Febrero 2017, 04:28 am
C, hola, de que otra manera puedo escribir esa notacion ? no entiendo ya que se supone que al hacer *envp++ es como si estumiera incrementando adentro del printf la variable :s por que cuando uno tiene por ejemplo int i, y luego hace i++ es lo mismo que tener i = i+1;, pero yo probe poniendo *envp = *envp + 1 y no funciona, tampoco funciona poniendo *envp = *(envp+1) :s



(http://i1123.photobucket.com/albums/l541/emiliosk8/dd_zps4ehfrsvy.png?t=1486178793)


Título: Re: otra manera de escribir *envp++
Publicado por: MAFUS en 5 Febrero 2017, 17:14 pm
Código
  1. ... *var++ ...

Es lo mismo que hacer
Código
  1. ... *var ...
  2. ++var;


Título: Re: otra manera de escribir *envp++
Publicado por: 7emiliosk8 en 5 Febrero 2017, 17:46 pm
Código
  1. ... *var++ ...

Es lo mismo que hacer
Código
  1. ... *var ...
  2. ++var;

Gracias, pero tengo una duda, el codigo era:
Citar
printf("%s\n",*envp++);


y tu me dices que es lo mismo que poner
... *var ...
++var;

pero si lo pongo asi tambien funciona :S
... *var ...
++*var;

porque ocurre eso ?


Título: Re: otra manera de escribir *envp++
Publicado por: MAFUS en 5 Febrero 2017, 23:58 pm
Si miras la tabla de prioridad de operadores de C verás que * y ++ tienen la misma prioridad y se evalúan de derecha a izquierda. Además de esto hay que recordar que el postincremento aumenta la variable después de que esta haya devuelto su valor.

Juntando todo esto tenemos que:
1. *envp++ -> Una expresión para operar
2. envp++ -> Evaluados los operadores que afectan a la variable se toma es postincremento.
3. Como envp++ es un postincremento primero se tomará el valor.
4. *envp -> Se toma el valor de la variable (una dirección de memoria) y se ejecuta el operador *, consiguiendo el valor que guarda dicha dirección.
5. envp++ -> Se termina de ejecutar el operador de postincremento sobre la variable y la hace apuntar a la siguiente posición de memoria.


Título: Re: otra manera de escribir *envp++
Publicado por: 7emiliosk8 en 6 Febrero 2017, 03:41 am
Si miras la tabla de prioridad de operadores de C verás que * y ++ tienen la misma prioridad y se evalúan de derecha a izquierda. Además de esto hay que recordar que el postincremento aumenta la variable después de que esta haya devuelto su valor.

Juntando todo esto tenemos que:
1. *envp++ -> Una expresión para operar
2. envp++ -> Evaluados los operadores que afectan a la variable se toma es postincremento.
3. Como envp++ es un postincremento primero se tomará el valor.
4. *envp -> Se toma el valor de la variable (una dirección de memoria) y se ejecuta el operador *, consiguiendo el valor que guarda dicha dirección.
5. envp++ -> Se termina de ejecutar el operador de postincremento sobre la variable y la hace apuntar a la siguiente posición de memoria.

Gracias por ser el unico en responder amigo, para ver si entendi, todos esos pasos ocurren por el hecho de estar dentro del printf ? , es decir si no tuviese ese printf y declarase en el main char *hola++, ahi simplemente incrementa de una vez la variable hola porque no hay nada mas que hacer ?

y otra cosa, si yo hubiese querido que se incrementase inmediatamente antes de hacer el printf ? como hubiese sido esa notacion ? en vez de poner esto
printf("%s",*envp++);   como seria?


Título: Re: otra manera de escribir *envp++
Publicado por: MAFUS en 6 Febrero 2017, 15:17 pm
En referente a tu primera pregunta: así es. De hecho la instrucción seguiría todos los pasos que te he dicho, pero al no haber nadie recogiendo el valor de ésta, el efecto final sería solo el incremento.

En referente a tu segunda pregunta: La instrucción sería ... *++envp .... De nuevo los operadores se evalúan de derecha a izquierda, por lo tanto ++ tiene prioridad sobre *. Como ++ en este caso es preincremento se ejecuta enseguida y después entrega el valor, que será pasado a * para conseguir el valor de la nueva dirección de memoria.


Título: Re: otra manera de escribir *envp++
Publicado por: 7emiliosk8 en 6 Febrero 2017, 18:23 pm
En referente a tu segunda pregunta: La instrucción sería ... *++envp .... De nuevo los operadores se evalúan de derecha a izquierda, por lo tanto ++ tiene prioridad sobre *. Como ++ en este caso es preincremento se ejecuta enseguida y después entrega el valor, que será pasado a * para conseguir el valor de la nueva dirección de memoria.

Buenos dias, gracias por responder de nuevo, pero una cosa que no logro entender es a que te refieres con de derecha a izq, ya que en ambos casos
*envp++
*++envp
la operacion ++ esta por delante del *  o sea en los dos casos tiene prioridad :s por que en la primera es entonces post incremento y en la otra pre ?

Ojala me entiendas, saludos!


Título: Re: otra manera de escribir *envp++
Publicado por: MAFUS en 6 Febrero 2017, 19:02 pm
Sigue este enlace, contiene la prioridad y precedencia de los operadores.
http://maxus.fis.usal.es/fichas_c.web/03xx_pags/0303.html
De izquierda a derecha quiere decir que :
A op1 B op2 C
Si op1 y op2 tienen misma prioridad primero se operará op1 y después op2.

De derecha a izquierda quiere decir que
A op1 B op2 C
Si op1 y op2 tienen misma prioridad primero se operará op2 y después op1.

Sobre tu última pregunta:
Sí primero se ejecuta el ++ pero el que esté en preincremento o postincremento produce efectos en tiempos diferentes.


Título: Re: otra manera de escribir *envp++
Publicado por: 7emiliosk8 en 6 Febrero 2017, 23:19 pm
Muchas gracias por toda la ayuda!!


Título: Re: otra manera de escribir *envp++
Publicado por: 7emiliosk8 en 7 Febrero 2017, 21:00 pm
@MAFUS , una ultima cosa :D

en este codigo str = *envp++;

lo que primero esta haciendo es asignar el valor de *envp a str y luego incrementar envp una vez?


Título: Re: otra manera de escribir *envp++
Publicado por: MAFUS en 7 Febrero 2017, 21:02 pm
Sí, así es.


Título: Re: otra manera de escribir *envp++
Publicado por: 7emiliosk8 en 7 Febrero 2017, 21:16 pm
Sí, así es.

Gracias master al fin pude entenderlo :D sos un crack!!!!, la ultima cosita y ahora si termino con esto :B

Me podrias decir que pasa en el compilador si tengo esto

Código
  1. while(*envp)
  2. {
  3. str = *envp;
  4. envp++;
  5. }
  6.  

En esta parte envp++; si yo la pusiera como *envp++; tambien funciona.

si lo analiso en el primer caso envp++; asigna el valor sin problema, pero en el segundo *envp++; como es post incremento primero el compilador toma en cuenta *envp (no se si sean los terminos pero es como que el compilador accede a ese valor y no hace nada mas)  y luego como no hay nada que hacer con *envp , incrementa envp una vez, al final en el 2do caso como que el compilador hace un paso de mas ?

Saludos master.


Título: Re: otra manera de escribir *envp++
Publicado por: ivancea96 en 7 Febrero 2017, 22:38 pm
En estos casos, ten en cuenta el orden en que se llaman los operadores: http://es.cppreference.com/w/cpp/language/operator_precedence (http://es.cppreference.com/w/cpp/language/operator_precedence)

Primero, el post-incremento(_++). Luego, la desreferencia(*).

Código
  1. *envp++;
Eso es lo mismo que:
Código
  1. *(envp++);
El post-incremento retorna el valor que tiene actualmente, e incrementa el valor de la variable (el retorno sigue siendo el antiguo).
Así pues, poner ese * ahí no hace nada funcional.

En caso de que te refieras a:
Código
  1. str = *envp++;
Pues hace lo esperado. str tendrá el valor de *envp, y luego se incrementará.
El compilador usualmente optimizará estas cosas, no es un tema realmente preocupante. Es más importante la legibilidad del código y, por supuesto, la funcionalidad.

Si programases C++, sí que podría tener algo más de repercusión al trabajar con objetos. Pero no mucha más.


Título: Re: otra manera de escribir *envp++
Publicado por: 7emiliosk8 en 7 Febrero 2017, 22:46 pm
En estos casos, ten en cuenta el orden en que se llaman los operadores: http://es.cppreference.com/w/cpp/language/operator_precedence (http://es.cppreference.com/w/cpp/language/operator_precedence)

Primero, el post-incremento(_++). Luego, la desreferencia(*).

Código
  1. *envp++;
Eso es lo mismo que:
Código
  1. *(envp++);
El post-incremento retorna el valor que tiene actualmente, e incrementa el valor de la variable (el retorno sigue siendo el antiguo).
Así pues, poner ese * ahí no hace nada funcional.

Hola, gracias por responder, pero no se supone que el post incremento es lo ultimo que se hace ? o sea si tengo *envp++ el compilador no le da preferencia al "*"?  es decir accede al * pero como no hay nada que hacer en el, luego pasa al post incremento... o estoy equivocado ?


Título: Re: otra manera de escribir *envp++
Publicado por: ivancea96 en 8 Febrero 2017, 16:05 pm
El _++ incrementa en el mismo momento. La diferencia con respecto al ++_ es que el post-incremento retorna el valor antiguo, y el pre-incremento retorna el nuevo valor.

Código
  1. int n = 0;
  2. int j = n++;
  3. // Cuando se ejecuta el n++, quedaría como:
  4. int j = 0;

Sin embargo:

Código
  1. int n = 0;
  2. int j = ++n;
  3. // Cuando se ejecuta el ++n, quedaría como:
  4. int j = 1;

Con estio quiero decir: ++_ y _++ son exactamente lo mismo, excepto en 2 aspectos: orden de ejecución y valor retornado.

Para comprobar que el _++ efectivamente incrementa el valor, puedes probar así:

Código
  1. #include <stdio.h>
  2.  
  3. int main(){
  4. int n = 1;
  5. printf("%i %i", n++, n);
  6. }


Título: Re: otra manera de escribir *envp++
Publicado por: 7emiliosk8 en 8 Febrero 2017, 19:36 pm
El _++ incrementa en el mismo momento. La diferencia con respecto al ++_ es que el post-incremento retorna el valor antiguo, y el pre-incremento retorna el nuevo valor.

Amigo pero si tu dices que ambos tienen igual importancia, si yo tuviera dos de esos en una operacion, cual se resuelve primero ? es decir si tuviera

a = ++b * b++;

o en este ejemplo que esta mas elaborado, como se resolveria ? (segun el compilador b queda con un valor de 13.)

Citar
int main()
{
  int a=1;
  int b = a++ + ++a * a++;
  printf("%d",b);
}


Título: Re: otra manera de escribir *envp++
Publicado por: ivancea96 en 8 Febrero 2017, 21:11 pm
Este tema es un poco complicado ya la verdad. En primer lugar, el comportamiento en estos casos es indefinido. http://es.cppreference.com/w/cpp/language/eval_order#Comportamiento_indefinido (http://es.cppreference.com/w/cpp/language/eval_order#Comportamiento_indefinido)

Aun siendo así, la explicación de que de 13 es esta:

Antes de nada, tengamos en cuenta un par de cosas: el post-incremento retorna un nuevo valor, nada extraño. Sin embargo, el pre-incremento retorna una referencia (lvalue) de la variable. Esto significa que ++n no se transforma en "5", por ejemplo. ++n se transforma en n. Con esto en cuenta, resolvámoslo:


Código
  1. int n = 1;
  2.  
  3. n++ + ++n * n++;
  4.  
  5. 1 + ++n * n++;
  6. // n = 2
  7.  
  8. 1 + n * n++; // Nótese que aquí cambiamos ++n por n, no por su valor, porque es una referencia, y el valor siempre estará vinculado a la variable
  9. // n = 3
  10.  
  11. 1 + n * 3;
  12. // n = 4
  13.  
  14. 1 + 4 * 3; // Llegados a este punto, sacamos el valor de esa n
  15.  
  16. 1 + 12
  17.  
  18. 13

Ese ++n puede generar un poco de confusión (a mi me la acaba de enerar, tuve que mirar el ensamblador que genera el compilador xD)

En fin, si bien esto es puramente "académico" y "curioso", pues eso, mejor evitar usar _++ y ++_ en donde puedan generar confusión (como poniendo varios en la misma sentencia).


Título: Re: otra manera de escribir *envp++
Publicado por: 7emiliosk8 en 8 Febrero 2017, 21:59 pm
Vaya XD que enredo, al menos como que lo entendi un poco, amigo, eso del ensamblador que genera el codigo me podrias explicar como usarlo o como tengo que buscar para poder aprender a utilizarlo y yo mismo ir practicando con otras formas de codigo.
aunque ya me quedo claro que no es recomendable utilizar este tipo de notacion jajaj, saludos!


Título: Re: otra manera de escribir *envp++
Publicado por: ivancea96 en 8 Febrero 2017, 23:14 pm
Si compilas con GCC, puedes pasar el argumento "-S" para que genere el ensamblador en vez de el binario. Además, pasarle -O0 para que no optimice el código (y así tener el código tal como tú lo generaste).

Por ejemplo, este es el ASM desglosado del programa que probé (suerte que lo recuperé de la papelera de reciclaje) (está en C++, pero ninguna parte importante):

Código
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5. int main(){
  6. int n = 1;
  7.  
  8. cout << n++ + ++n * n++;
  9. }
  10.  
  11. /*
  12.  
  13.  
  14. movl    $1, n ; int n = 1
  15.  
  16. movl    n, %edx
  17. leal    1(%edx), %eax
  18. movl    %eax, n ; n++ (first, edx = old value)
  19.  
  20. addl    $1, n ; ++n
  21.  
  22. movl    n, %eax
  23. leal    1(%eax), %ecx
  24. movl    %ecx, n ; n++ (second, eax = old value)
  25.  
  26. imull   n, %eax
  27.  
  28. addl    %edx, %eax
  29.  
  30.  
  31. */

No sé si controlas ensamblador, y no es parte del tema, pero como breve resumen:
movl mueve el valor del primer operando al segundo.
leal es más complejo. pero aquí, en resumen, cuando pone 1(operando), lo que hace es sumarle 1 al operando y guardarlo en el segundo operando
imull multiplica y almacena el resultado en el segundo operando
addl suma y almacena elr esultado en el segundo operando

Separé cada "operador" por un salto de línea. (Inicialmente no ponía "n", ponía -12(%esp), que es donde se almacenan las variables locales. Pero lo cambié a n por legibilidad.

Y bueno, el ensamblador no miente. Primero, mueve un 1 a n.
Luego, hace el primer post-incremento, y almacena el valor antiguo (que es el que se suma realmente), en edx (registro, que serían como las variables de ASM).
Siguiente, hace el pre-incremento. Sin ir más lejos, añade 1. Trivial.
Luego, segundo post-incremento. Incrementa n, y almacena el valor antiguo en eax.

Y ahora las otras operaciones. Empezamos ya con el problema que había. Hace imull n, %eax. eax es el valor del post-incremento, todo correcto, pero, como vimos, n lo ha incrementado ya las 3 veces, así que va a multiplicar por ese valor.

Y finalmente, la suma, trivial también.

God bless you, y recuerda que si tú juegas con el lenguaje, el lenguaje jugará contigo :X


Título: Re: otra manera de escribir *envp++
Publicado por: 7emiliosk8 en 9 Febrero 2017, 17:58 pm
Sos un master, muchas gracias por la explicacion, bless.