EDIT Advertencia de salud pública: esta pregunta incluye una suposición falsa sobre el comportamiento indefinido. Ver respuesta aceptada¿Cómo hacer un doble fragmento sin un comportamiento indefinido?
Después de leer recent blog post, he estado pensando mucho acerca de la practicidad de evitar todos los estándares: suposiciones indefinidas en los códigos C y C++. Aquí hay un fragmento cortado de C++, para hacer un sin firmar, además de 128 bits ...
void c_UInt64_Pair::operator+= (const c_UInt64_Pair &p)
{
m_Low += p.m_Low;
m_High += p.m_High;
if (m_Low < p.m_Low) m_High++;
}
Esto se basa claramente en supuestos sobre el comportamiento de desbordamiento. Obviamente, la mayoría de las máquinas pueden admitir un entero binario del tipo correcto (aunque quizás construyendo fragmentos de 32 bits o lo que sea), pero aparentemente hay una posibilidad creciente de que el optimizador pueda explotar el comportamiento no definido de las normas aquí. Es decir, la única forma en que la condición m_Low < p.m_Low
puede pasar es si m_Low += p.m_Low
se desborda, lo que es un comportamiento indefinido, por lo que el optimizador puede decidir legalmente que la condición siempre falla. En cuyo caso, este código simplemente se rompe.
La pregunta es, por lo tanto ...
¿Cómo se puede escribir una versión razonablemente eficiente de los anteriores sin depender de un comportamiento indefinido?
Supongamos que tiene un entero de máquina binaria de 64 bits apropiado, pero que tiene un compilador malintencionado que siempre interpretará su comportamiento indefinido de la peor manera posible (o imposible). Además, suponga que no tiene tiene alguna biblioteca incorporada, intrínseca especial o lo que sea que lo haga por usted.
EDITAR pequeña aclaración - esto no es sólo acerca de la detección de desbordamiento, sino también asegurar que tanto m_Low y m_High terminan con el módulo correcto 2^64 resultados, que es también normas no definido.
1/Esto no es C. ¿Por qué etiqueta esta pregunta "C"? 2/Si esto fuera C, y quizás incluso en C++, esto no dependería de un comportamiento indefinido: los desbordamientos de tipos integrales sin signo se definen y tienen un comportamiento de módulo: 6.2.5.9 en el estándar C99. –
@Pascal: en realidad, ver la sección 5.4 del borrador más reciente (no tengo el estándar C++ 03 aquí, pero creo que el comportamiento no ha cambiado) - "Si durante la evaluación de una expresión, el resultado no está matemáticamente definido o no en el rango de valores representables para su tipo, el comportamiento no está definido ". –
@Pascal - (1) la pregunta es igualmente sobre C y C++. Proporcionar un ejemplo en una sola no significa que la pregunta es solo sobre esa. (2) ¿Cuándo sucedió eso? Si es verdad, es la respuesta (es posible que C++ aún no haya importado la regla C relevante, pero si no, sin duda lo hará), así que póngala en una respuesta con una referencia y la aceptaré. – Steve314