2011-05-16 30 views
10

Todavía estoy un poco confundido después de leer el tema this. ¿Está bien definida la expresión C++ *d++ = ~(*d);? Sí, sé que las expresiones compuestas como esta son feas. No lo escribí.¿Este código está bien definido?

veo una ligera diferencia en el conjunto generado cuando lo comparo con:

*d = ~(*d); 
d++; 

Asamblea:

*d++ = ~(*d); 
0x83384 LDR   R3,[R0 <d>,4]  <<diff 
0x83388 ADD   R1 <c>, R1 <c>, 1 
0x8338c MVN   R3, R3 
0x83390 STR   R3,[R0 <d>],4 

vs

*d = ~(*d); 
d++; 
0x83384 LDR   R3,[R0 <d>] 
0x83388 ADD   R1 <c>, R1 <c>, 1 
0x8338c MVN   R3, R3 
0x83390 STR   R3,[R0 <d>],4 

Gracias!

+0

Todo lo que el ensamblador le dirá es qué hizo esta versión particular de este compilador en particular con la configuración que utilizó en este momento en particular. No dice nada de lo que está garantizado o no por el estándar. –

+0

Gracias. Inicialmente pensé que podría ser útil ver qué estaba generando el compilador en el contexto de esta pregunta. Ahora veo que cualquier cosa (en el caso indefinido) podría haberse generado potencialmente. – Mav3rick

Respuesta

9
*d++ = ~(*d); 

En esta expresión no objeto es tener un nuevo valor almacenado para que sea más que una vez. El valor de d + 1 se almacena en d como efecto secundario del operador de incremento (d++) y el valor del objeto apuntado por d antes de que el operador de asignación registre este incremento.

La cuestión es que d se lee, no sólo para determinar el valor a ser escrito de nuevo a él (es decir d + 1), pero también se lee para determinar la dirección para leer desde la derecha de la parte sub-expresión ~(*d).

Esto viola la tercera frase de la norma ISO/IEC 14882: 2003 5 [expr]/4 (primera frase omitida por razones de brevedad):

[...] Entre el anterior y el siguiente punto de la secuencia de un escalar objeto tendrá su valor almacenado modificado como máximo una vez por la evaluación de una expresión. Además, se accederá al valor anterior solo para determinar el valor que se almacenará. Los requisitos de este párrafo se cumplirán para cada orden permitida de las subexpresiones de una expresión completa; de lo contrario, el comportamiento no está definido.

+0

Esta es una explicación muy útil. Gracias. – Mav3rick

11

Su expresión tiene (en contraposición a no especificado) un comportamiento indefinido. El código de ensamblaje también podría jugar Beethoven noveno y aún cumplir con el estándar.

De la Santa Estándar, capítulo 5, versículo 4:

entre el anterior y el siguiente punto de la secuencia de un objeto escalar tendrá su valor almacenado modificado como máximo una vez por la evaluación de una expresión.

Por lo tanto, el código está mal formado. No sé si un compilador estándar conforme es requirió para emitir un diagnóstico, pero me han mordido bastantes veces por esto que estoy listo para apostar que no lo es.

Consulte la excelente exposición de @Prasoon Saurav there para obtener más información.

+0

Ojalá fuera así. – Femaref

+0

* ¡ESO sería muy increíble! :) – FrustratedWithFormsDesigner

+0

@coward downvoter: aclare sus intenciones. Estoy bastante seguro de que es UB por el enlace al que apunta OP, pero podría estar equivocado. –

1

No se sabe cuándo se evalúa el ++. Supongo que su compilador evalúa antes del ~(*d) que se traduce en

*d = ~(*(d+1)); 

así su dicrepancy.

+0

No suponga nada. No hay nada que suponer, el código está mal formado según el estándar C++ ISO. –

+0

Creo que quiso decir * d = ~ (* (d + 1)) si se refiere al efecto ++ antes de la búsqueda de rhs. –

+0

@ Alexander C., creo que Christian estaba diciendo que el ejemplo de desensamblaje muestra que algún compilador particular hizo el incremento primero, y esto sería diferente al ensamblado (o expectativa) del ordenamiento opuesto. –

Cuestiones relacionadas