A pesar de las muchas respuestas no útiles que ha recibido esta pregunta, creo que tiene mucho mérito en el contexto de una base de código heredado.
Imagine que se han acumulado muchas afirmaciones a lo largo de los años, pero como no existía la costumbre de compilar/probar con NDEBUG, algunos efectos secundarios se han filtrado en las afirmaciones y ahora no se atreve a deshabilitar las afirmaciones nunca más.
Puede activar NDEBUG y detectar algunas fallas de prueba en su banco de pruebas, pero no es totalmente sencillo vincular una falla de prueba con la afirmación 'efectiva' porque puede estar muy lejos del punto donde detecta la falla . E incluso un conjunto de pruebas con buena cobertura no se puede confiar en que esté completo.
Puede realizar una revisión del código de todas las aserciones en el código, pero esto es potencialmente mucho trabajo y propenso a errores humanos. Sería mucho mejor si algún análisis estático ya puede eliminar todas las afirmaciones donde pruebe que no aparecen efectos secundarios y solo debe investigar aquellos casos en los que no se garantiza su ausencia.
Así es como puede usar el optimizador de su compilador para llevar a cabo dicho análisis estático. Supongamos que se organizan para sustituir a la definición de la macro assert
por:
extern int not_supposed_to_survive;
#define assert(expr) ((void)(not_supposed_to_survive || (expr)))
Si expr
tiene ningún efecto secundario, la ejecución del efecto está condicionada a que el valor de la variable global not_supposed_to_survive
. Pero si expr
no tiene ningún efecto secundario, el valor de la variable global no importa (tenga en cuenta que el resultado expr
se descarta). Un buen optimizador lo sabe y eliminará la carga de la variable global not_supposed_to_survive
, de ahí el nombre de la variable.
Si nuestro programa no contiene una definición del símbolo not_supposed_to_survive
, obtendremos un error de enlace cuando la carga no se elimine y podemos usar esto para detectar una afirmación potencialmente efectiva.
E.g. con gcc 4.8:
int g;
int foo() { return ++g; }
int main() {
assert(foo());
return 0;
}
gcc -O2 assert_effect.c
/tmp/ccunynya.o: In function `main':
assert_effect.c:(.text.startup+0x2): undefined reference to `not_supposed_to_survive'
collect2: error: ld returned 1 exit status
¡El compilador me ayudó a encontrar una afirmación dudosa! Por otro lado, si reemplazo ++g
por g+1
, el error de enlace desaparece y no tengo que investigarlo. De hecho, esa afirmación está garantizada inofensiva.
Por supuesto, el concepto de "efectos secundarios probables" está limitado por lo que el optimizador "puede ver". Para un análisis más preciso, recomendaría utilizar la optimización de tiempo de enlace (gcc -flto
) para analizar en unidades de compilación.
Actualización: Apliqué esto en una base de código C++ de la vida real usando gcc 5.3. Para utilizar la optimización de tiempo de enlace, básicamente utiliza gcc -flto -g
como el compilador/enlazador (la opción -g
en el compilador/enlazador para obtener una referencia de línea en los errores de enlace) y gcc-ar
y gcc-ranlib
como archivador/indexador para las bibliotecas estáticas.
Esta configuración podría reducir enormemente el número de afirmaciones que tuve que investigar. Con una mano de obra mínima, pude obtener las afirmaciones limpias.Los falsos positivos que todavía tenía que bajar manualmente se debieron a:
- función virtual llama
- no triviales Bucles/recurrencias (donde el optimizador no puede demostrar que son finitos)
además, también me gustaría conseguir algunas afirmaciones que, efectivamente contenían efectos secundarios, pero son inofensivos o no significativos, tales como:
- funciones de registro que contienen estados
- Funciones esa caché de su resultado (s)
No, GCC no comprueba si las funciones tienen efectos secundarios. –
Quizás requiera una revisión de código antes de la confirmación. –
Para aclarar mi pregunta, no contamos con los recursos para realizar una revisión manual del código en algunos de estos repositorios. Para nuestros de alta prioridad, hacemos una revisión del código. Estaba buscando algo automatizado que nos ahorrara tener que rechazar compromisos para estos errores triviales. – Matthew