w3schools script operadores logicos google distinto condicionales comparar comparacion cadenas asignacion javascript c semantics puzzle

logicos - operadores javascript w3schools



¿Por qué(x+= x+= 1) se evalúa de manera diferente en C y Javascript? (6)

Al menos en C, este es un comportamiento indefinido. La expresión x += x+= 1; tiene dos puntos de secuencia : uno implícito justo antes de que comience la expresión (es decir, el punto de secuencia anterior), y luego otra vez en el ; . Entre estos dos puntos de secuencia, x se modifica dos veces y esto se declara explícitamente como un comportamiento indefinido por el estándar C99. El compilador es libre de hacer lo que quiera en este momento, incluso hacer que los demonios salgan volando por la nariz. Si tiene suerte, simplemente hace lo que espera, pero simplemente no hay garantía para eso.

Esta es la misma razón por la que x = x++ + x++; no está definido en C. Consulte también la C-FAQ para obtener más ejemplos y explicaciones de esto o la entrada de Preguntas frecuentes sobre StackOverflow C ++ Sin definir Comportamiento y puntos de secuencia (AFAIK, las reglas de C ++ para esto son las mismas que para C).

Si el valor de la variable x es inicialmente 0, la expresión x += x += 1 se evaluará en 2 en C y en 1 en Javascript.

La semántica para C me parece obvia: x += x += 1 se interpreta como x += (x += 1) que es, a su vez, equivalente a

x += 1 x += x // where x is 1 at this point

¿Cuál es la lógica detrás de la interpretación de Javascript? ¿Qué especificación impone tal comportamiento? (Cabe señalar, por cierto, que Java está de acuerdo con Javascript aquí).

Actualización: Resulta que la expresión x += x += 1 tiene un comportamiento indefinido de acuerdo con el estándar C (gracias, John Bode , DarkDust , Drew Dormann ), que parece arruinar todo el punto de la pregunta para algunos lectores. La expresión puede ser compatible con los estándares insertando una función de identidad en ella de la siguiente manera: x += id(x += 1) . La misma modificación se puede hacer en el código de Javascript y la pregunta sigue siendo como se indica. Suponiendo que la mayoría de los lectores puedan entender el punto detrás de la formulación "no conforme con los estándares", lo mantendré porque es más conciso.

Actualización 2: Resulta que, según C99, la introducción de la función de identidad probablemente no resuelva la ambigüedad. En este caso, estimado lector, considere que la pregunta original pertenece a C ++ en lugar de C99, donde "+ =" probablemente ahora se puede considerar de manera segura como un operador recargable con una secuencia de operaciones definida de forma única. Es decir, x += x += 1 ahora es equivalente a operator+=(x, operator+=(x, 1)) . Lo siento por el largo camino hacia el cumplimiento de las normas.


En C, x += x += 1 es un comportamiento indefinido .

No se puede contar con que los resultados se produzcan de forma coherente porque no está definido intentar actualizar el mismo objeto dos veces entre los puntos de secuencia .


JavaScript y Java tienen reglas de evaluación de izquierda a derecha bastante estrictas para esta expresión. C no (incluso en la versión que proporcionó que tiene la función de identidad interviniendo).

La especificación de ECMAScript que tengo (3ª edición, que admito que es bastante antigua, la versión actual se puede encontrar aquí: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf ) dice que los operadores de asignación de compuestos se evalúan así:

11.13.2 Asignación compuesta (op =)

La producción AssignmentExpression: LeftHandSideExpression @ = AssignmentExpression, donde @ representa uno de los operadores indicados anteriormente, se evalúa de la siguiente manera:

  1. Evaluar LeftHandSideExpression.
  2. Llame a GetValue (Resultado (1)).
  3. Evaluar AssignmentExpression.
  4. Llame a GetValue (Resultado (3)).
  5. Aplique operator @ a Resultado (2) y Resultado (4).
  6. Call PutValue (Resultado (1), Resultado (5)).
  7. Resultado devuelto (5)

Observa que Java tiene el mismo comportamiento que JavaScript. Creo que su especificación es más legible, por lo que publicaré algunos fragmentos aquí ( http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.7 ):

15.7 Orden de evaluación

El lenguaje de programación Java garantiza que los operandos de los operadores parecen ser evaluados en un orden de evaluación específico, es decir, de izquierda a derecha.

Se recomienda que el código no se base fundamentalmente en esta especificación. El código suele ser más claro cuando cada expresión contiene a lo sumo un efecto secundario, como su operación más externa, y cuando el código no depende exactamente de qué excepción surge como consecuencia de la evaluación de izquierda a derecha de las expresiones.

15.7.1 Evaluar primero el operando de la mano izquierda El operando de la izquierda de un operador binario parece ser evaluado por completo antes de que se evalúe cualquier parte del operando de la derecha. Por ejemplo, si el operando de la izquierda contiene una asignación a una variable y el operando de la derecha contiene una referencia a esa misma variable, entonces el valor producido por la referencia reflejará el hecho de que la asignación ocurrió primero.

...

Si el operador es un operador de asignación compuesta (§15.26.2), la evaluación del operando de la izquierda incluye tanto recordar la variable que el operando de la izquierda denota como recuperar y guardar el valor de esa variable para usar en la operación de combinación implícita .

Por otro lado, en el ejemplo de comportamiento no indefinido donde proporciona una función de identidad intermedia:

x += id(x += 1);

Si bien no es un comportamiento indefinido (ya que la llamada a la función proporciona un punto de secuencia), sigue siendo un comportamiento no especificado si la x más a la izquierda se evalúa antes o después de la llamada a la función. Entonces, si bien no es un comportamiento indefinido de ''todo vale'', al compilador C todavía se le permite evaluar ambas variables x antes de llamar a la función id() , en cuyo caso el valor final almacenado en la variable será 1 :

Por ejemplo, si x == 0 para comenzar, la evaluación podría verse así:

tmp = x; // tmp == 0 x = tmp + id( x = tmp + 1) // x == 1 at this point

O podría evaluarlo así:

tmp = id( x = x + 1); // tmp == 1, x == 1 x = x + tmp; // x == 2 at this point

Tenga en cuenta que el comportamiento no especificado es sutilmente diferente del comportamiento no definido, pero aún así no es un comportamiento deseable.


Todas las expresiones de JavaScript se evalúan de izquierda a derecha.

La asociatividad de ...

var x = 0; x += x += 1

estarán...

var x = 0; x = (x + (x = (x + 1)))

Por lo tanto, debido a su evaluación de izquierda a derecha, el valor actual de x se evaluará antes de que se realice cualquier otra operación.

El resultado podría verse así ...

var x = 0; x = (0 + (x = (0 + 1)))

... que será claramente igual a 1 .

Asi que...

var x = 0; x = (x + (x = (x + 1))); // x = (0 + (x = (0 + 1))); // 1 x = (x + (x = (x + 1))); // x = (1 + (x = (1 + 1))); // 3 x = (x + (x = (x + 1))); // x = (3 + (x = (3 + 1))); // 7


Varios temas están en juego aquí.

Lo primero y más importante es esta parte de la especificación del lenguaje C:

6.5 Expresiones
...
2 Entre el punto de secuencia anterior y el siguiente, un objeto tendrá su valor almacenado modificado a lo sumo una vez por la evaluación de una expresión. 72) Además, el valor anterior se leerá solo para determinar el valor que se almacenará. 73)
...
72) Un indicador de estado de punto flotante no es un objeto y se puede establecer más de una vez dentro de una expresión.

73) Este párrafo representa expresiones de declaración no definidas como

i = ++i + 1; a[i++] = i; mientras que permite

i = i + 1; a[i] = i;

Énfasis mío.

La expresión x += 1 modifica x (efecto secundario). La expresión x += x += 1 modifica x dos veces sin un punto de secuencia intermedio, y no lee el valor anterior solo para determinar el nuevo valor que se almacenará; por lo tanto, el comportamiento es indefinido (lo que significa que cualquier resultado es igualmente correcto). Ahora, ¿por qué demonios sería eso un problema? Después de todo, += es asociativo por la derecha, y todo se evalúa de izquierda a derecha, ¿verdad?

Incorrecto.

3 La agrupación de operadores y operandos se indica mediante la sintaxis. 74) Excepto como se especifica más adelante (para la función-call () , && , || , ?: Y operadores de coma), el orden de evaluación de las subexpresiones y el orden en el que se producen los efectos secundarios no están especificados .
...
74) La sintaxis especifica la prioridad de los operadores en la evaluación de una expresión, que es el mismo que el orden de las principales subcláusulas de esta subcláusula, la prioridad más alta primero. Así, por ejemplo, las expresiones permitidas como los operandos del operador binario + (6.5.6) son aquellas expresiones definidas en 6.5.1 a 6.5.6. Las excepciones son expresiones de conversión (6.5.4) como operandos de operadores unarios (6.5.3) y un operando contenido entre cualquiera de los siguientes pares de operadores: paréntesis de agrupación () (6.5.1), corchetes de suscripción [] (6.5) .2.1), paréntesis de llamada a función () (6.5.2.2) y el operador condicional ?: (6.5.15).

Énfasis mío.

En general, la precedencia y la asociatividad no afectan el orden de evaluación ni el orden en que se aplican los efectos secundarios. Aquí hay una posible secuencia de evaluación:

t0 = x + 1 t1 = x + t0 x = t1 x = t0

Ups. No es lo que queríamos.

Ahora, otros lenguajes como Java y C # (y supongo que Javascript) especifican que los operandos siempre se evalúan de izquierda a derecha, por lo que siempre hay un orden de evaluación bien definido.


x += x += 1; Es un comportamiento indefinido en C.

La declaración de expresión viola las reglas de puntos de secuencia.

(C99, 6.5p2) "Entre el punto de secuencia anterior y siguiente, un objeto debe tener su valor almacenado modificado a lo sumo una vez por la evaluación de una expresión".