otra manera de escribir *envp++

Iniciado por 7emiliosk8, 5 Febrero 2017, 04:28 AM

0 Miembros y 1 Visitante están viendo este tema.

MAFUS


7emiliosk8

Cita de: MAFUS en  7 Febrero 2017, 21:02 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


while(*envp)
{
str = *envp;
envp++;
}


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.

ivancea96

En estos casos, ten en cuenta el orden en que se llaman los operadores: http://es.cppreference.com/w/cpp/language/operator_precedence

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

*envp++;
Eso es lo mismo que:
*(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:
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.

7emiliosk8

Cita de: 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

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

*envp++;
Eso es lo mismo que:
*(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 ?

ivancea96

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.

int n = 0;
int j = n++;
// Cuando se ejecuta el n++, quedaría como:
int j = 0;


Sin embargo:

int n = 0;
int j = ++n;
// Cuando se ejecuta el ++n, quedaría como:
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í:

#include <stdio.h>

int main(){
int n = 1;
printf("%i %i", n++, n);
}

7emiliosk8

#15
Cita de: 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.

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);
}

ivancea96

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

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:


int n = 1;

n++ + ++n * n++;

1 + ++n * n++;
// n = 2

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
// n = 3

1 + n * 3;
// n = 4

1 + 4 * 3; // Llegados a este punto, sacamos el valor de esa n

1 + 12

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).

7emiliosk8

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!

ivancea96

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 (cpp) [Seleccionar]
#include <iostream>

using namespace std;

int main(){
int n = 1;

cout << n++ + ++n * n++;
}

/*


movl    $1, n ; int n = 1

movl    n, %edx
leal    1(%edx), %eax
movl    %eax, n ; n++ (first, edx = old value)

addl    $1, n ; ++n

movl    n, %eax
leal    1(%eax), %ecx
movl    %ecx, n ; n++ (second, eax = old value)

imull   n, %eax

addl    %edx, %eax


*/


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

7emiliosk8

Sos un master, muchas gracias por la explicacion, bless.