¿Cómo puedo saber si el compilador rompió mi código y qué hago si era el compilador?

12

De vez en cuando, el código C ++ no funcionará cuando se compile con un cierto nivel de optimización. Puede ser que el compilador realice una optimización que rompa el código o puede ser un código que contiene un comportamiento indefinido que le permite al compilador hacer lo que se siente.

Supongamos que tengo un fragmento de código que se rompe cuando se compila solo con un nivel de optimización más alto. ¿Cómo puedo saber si es el código o el compilador y qué hago si es el compilador?

    
pregunta sharptooth 26.09.2011 - 09:50

11 respuestas

17

Yo diría que es una apuesta segura en 99.9 ...% la gran mayoría de los casos en que es su código, no el compilador, que está roto. E incluso en el caso extraordinario cuando se trata del compilador, es probable que esté utilizando alguna característica de lenguaje oscuro de una manera inusual, para la cual el compilador específico no está preparado; en otras palabras, lo más probable es que puedas cambiar tu código para que sea más idiomático y evitar el punto débil del compilador. En cualquier caso, si puede probar encontrar un error en el compilador (según la especificación del idioma), infórmeselo a los desarrolladores del compilador para que puedan solucionarlo en algún momento.

Sé que esta no es una respuesta directa a tu pregunta, es posible que otros puedan brindarte una mejor ayuda en esto.

    
respondido por el Péter Török 26.09.2011 - 09:57
13

Como de costumbre, como con cualquier otro error: realice un experimento controlado. Reduzca el área sospechosa, desactive las optimizaciones para todo lo demás y comience a variar las optimizaciones aplicadas a esa porción de código. Una vez que obtenga una reproducibilidad del 100%, comience a variar su código, introduciendo cosas que podrían romper ciertas optimizaciones (por ejemplo, introduzca un posible alias de puntero, inserte llamadas externas con posibles efectos secundarios, etc.). Ver el código de ensamblaje en un depurador también podría ayudar.

    
respondido por el SK-logic 26.09.2011 - 10:01
9

Examine el código de ensamblaje resultante y vea si hace lo que su fuente solicita. Recuerde que las probabilidades son muy altas de que su código sea realmente defectuoso de alguna manera no obvia.

    
respondido por el Loren Pechtel 26.09.2011 - 19:48
6

En más de 30 años de programación, el número de errores de compilación genuinos (generación de código) que he encontrado sigue siendo solo de ~ 10. El número de errores propios (y de otros) que he encontrado y corregido en el mismo período es probablemente > 10,000. Mi "regla de oro" es que la probabilidad de que un error se deba al compilador es < 0.001.

    
respondido por el Paul R 26.09.2011 - 11:26
5

Comencé a escribir un comentario y luego decidí que era demasiado largo y preciso.

Yo diría que es tu código el que está roto. En el improbable caso de que hayas descubierto un error en el compilador, deberías informarlo a los desarrolladores del compilador, pero ahí es donde termina la diferencia.

La solución es identificar el constructo ofensivo y refactorizarlo para que haga la misma lógica de manera diferente. Lo más probable es que solucione el problema, ya sea que el error esté de su lado o en el compilador.

    
respondido por el littleadv 26.09.2011 - 10:02
5
  1. Vuelva a leer su código a fondo. Asegúrese de que no está haciendo cosas con efectos secundarios en ASSERTs, u otras declaraciones específicas de depuración (o más generales, de configuración). También recuerde que en una memoria de compilación de depuración se inicializa de manera diferente: los valores del indicador de indicador pueden verificarse aquí: Depuración - Representaciones de asignación de memoria . Cuando se ejecuta desde dentro de Visual Studio, casi siempre está utilizando el montón de depuración (incluso en modo de lanzamiento) a menos que especifique explícitamente con una variable de entorno que esto no es lo que desea.
  2. Comprueba tu construcción. Es común tener problemas con compilaciones complejas en otros lugares que no sean el compilador real, ya que las dependencias suelen ser las culpables. Sé que "has intentado reconstruir completamente" es una respuesta casi tan exasperante como "has intentado reinstalar Windows", pero a menudo ayuda. Intenta: a) Reiniciar. b) Eliminar todos sus archivos intermedios y de salida MANUALMENTE y reconstruir.
  3. Revise su código para buscar posibles ubicaciones donde pueda invocar un comportamiento indefinido. Si ha estado trabajando en C ++ por un tiempo, sabrá que hay algunos lugares donde piensa "No estoy completamente seguro de que puedo suponer que ..." - busque en Google o pregunte aquí sobre ese tema en particular tipo de código para ver si es un comportamiento indefinido o no.
  4. Si aún así no parece ser el caso, genere una salida preprocesada para el archivo que está causando los problemas. Una expansión de macros inesperada puede causar todo tipo de diversión (me acuerdo de cuando un colega decidió que una macro con el nombre de H sería una buena idea ...). Examine la salida preprocesada para detectar cambios inesperados entre las configuraciones de su proyecto.
  5. Último recurso: ahora que realmente estás en la tierra de errores del compilador: mira la salida del ensamblaje. Esto podría requerir un poco de excavación y lucha solo para entender lo que realmente está haciendo el ensamblaje, pero en realidad es bastante informativo. También puede utilizar las habilidades que adquiera aquí para evaluar las microoptimizaciones, por lo que no todo está perdido.
respondido por el Joris Timmermans 26.09.2011 - 10:30
2

Si desea saber si es su código o el compilador, debe conocer perfectamente la especificación de C ++.

Si la duda persiste, debe conocer perfectamente el ensamblado x86.

Si no está de humor para aprender a la perfección, entonces es casi seguro que su compilador resuelva de manera diferente dependiendo del nivel de optimización.

    
respondido por el mouviciel 26.09.2011 - 10:06
1

Es más probable que un error de compilación en un código estándar o un error interno de compilación sea incorrecto. Pero he oído hablar de compiladores que optimizan bucles olvidando incorrectamente algunos efectos secundarios que puede causar un método.

No tengo sugerencias sobre cómo saber si es usted o el compilador. Puedes probar con otro compilador.

Un día me preguntaba si era mi código o no, y alguien me sugirió que me atendiera. Gasté los 5 o 10 minutos para ejecutar mi programa con él (creo que valgrind --leak-check=yes myprog arg1 arg2 lo hizo pero jugué con otras opciones) e inmediatamente me mostró UNA línea que se ejecuta en un caso específico, que era el problema. Entonces mi aplicación se ejecutó sin problemas desde entonces sin errores extraños, errores o comportamiento extraño. Valgrind u otra herramienta como esta es una buena manera de saber si es su código.

Nota al margen: una vez me pregunté por qué el rendimiento de mi aplicación apestó. Resultó que todos mis problemas de rendimiento también estaban en una línea. Escribí for(int i=0; i<strlen(sz); ++i) { . El sz fue unos pocos mb. Por alguna razón, el compilador ejecutó strlen todas las veces incluso después de la optimización. Una línea puede ser un gran problema. Desde actuaciones hasta choques

    
respondido por el user2528 14.01.2012 - 08:45
1

Una situación cada vez más común es que los compiladores rompen el código escrito para dialectos de C que admite comportamientos no exigidos por la Norma, y permitió que el código dirigido a esos dialectos sea más eficiente de lo que podría ser el código estrictamente conforme. En tal caso, sería injusto describirlo como un código "roto" que sería 100% confiable en los compiladores que implementaron el dialecto objetivo, o describir como "roto" el compilador que procesa un dialecto que no admite la semántica requerida. . En su lugar, los problemas se derivan simplemente del hecho de que el lenguaje procesado por los compiladores modernos con las optimizaciones habilitadas difiere de los dialectos que solían ser populares (y aún son procesados por muchos compiladores con las optimizaciones deshabilitadas, o por algunos incluso con las optimizaciones habilitadas). / p>

Por ejemplo, se escribe una gran cantidad de código para los dialectos que reconocen como legítimos una cantidad de patrones de alias de punteros que no son obligatorios por la interpretación de gcc de la Norma, y hace uso de dichos patrones para permitir Una traducción directa del código para que sea más legible y eficiente de lo que sería posible bajo la interpretación de gcc de la C Estándar. Tal código puede no ser compatible con gcc, pero eso no lo hace implica que está roto. Simplemente se basa en extensiones que solo gcc ayudas con optimizaciones desactivadas.

    
respondido por el supercat 27.06.2016 - 00:50
0

Aísle el punto problemático y compare el comportamiento observado con lo que debería suceder de acuerdo con las especificaciones del idioma. Definitivamente no es fácil, pero eso es lo que tienes que hacer para saber (y no solo asumir ).

Probablemente no sería tan meticuloso. Más bien, le pediría al foro de soporte del fabricante del compilador / lista de correo. Si es realmente un error en el compilador, entonces podrían solucionarlo. Probablemente sería mi código de todos modos. Por ejemplo, las especificaciones de idioma con respecto a la visibilidad de la memoria en los subprocesos pueden ser muy poco intuitivas, y podrían ser evidentes solo cuando se utilizan algunos indicadores de optimización específicos, en algún hardware específico (!) Algunos comportamientos podrían no estar definidos por la especificación, por lo que podría funcionar con algunos compiladores / algunas banderas y no funcionar con otras, etc.

    
respondido por el Joonas Pulakka 26.09.2011 - 10:05
0

Lo más probable es que su código tenga algún comportamiento indefinido (como explicaron otros, es mucho más probable que tenga errores en su código que en el compilador, incluso si los compiladores de C ++ son tan complejos que tienen errores, incluso la especificación de C ++ tiene errores de diseño). Y UB puede estar aquí incluso si el ejecutable compilado funciona (por mala suerte).

Así que deberías leer el blog de Lattner ' Lo que todo programador de C debería saber sobre el comportamiento indefinido (la mayor parte se aplica también a C ++ 11).

La herramienta valgrind y el reciente -fsanitize= opciones de instrumentación a GCC (o Clang / LLVM ), también debería ser útil. Y, por supuesto, habilita todas las advertencias: g++ -Wall -Wextra

    
respondido por el Basile Starynkevitch 27.06.2016 - 13:17

Lea otras preguntas en las etiquetas