312 votos

¿Cómo puedo saber qué partes del código se utilizan nunca?

He legado de código de C++ que se supone que debo quitar código no utilizado. El problema es que el código de base es grande.

¿Cómo puedo saber que el código no se llama nunca/nunca se utiliza?

197voto

Matthieu M. Puntos 101624

Existen dos variedades de código no utilizado:

  • el local, que es, en algunas de las funciones de algunos de los caminos o las variables no están en uso (o usado pero en ningún modo significativo, como por escrito, pero nunca de leer)
  • a todo el mundo: funciones que nunca se denominan, objetos globales que nunca acceder

Para el primer tipo, un buen compilador puede ayudar a:

  • -Wunused (GCC, Clang) debe advertir sobre variables sin usar, Clang sin usar el analizador, incluso se ha incrementado a advertir acerca de las variables que se han leído nunca (aunque usa).
  • -Wunreachable-code (mayores de GCC, retirado en 2010) se debe advertir sobre los bloques que nunca se accede (lo que sucede con los rendimientos o las condiciones que siempre se evalúe a true)
  • no hay ninguna opción que conozco de advertir acerca de inusitada catch bloques, debido a que el compilador lo general no puede demostrar que no es la excepción será lanzado.

Para el segundo tipo, es mucho más difícil. Estáticamente, se requiere de todo el programa de análisis, y aunque vínculo optimización del tiempo puede realmente eliminar del código muerto, en la práctica, el programa ha sido tan transformada en el momento en que se realiza es casi imposible de transmitir información significativa para el usuario.

Por consiguiente, existen dos enfoques:

  • El teórico es usar un analizador estático. Una pieza de software que se va a examinar el conjunto de código a la vez con gran detalle y encontrar todas las vías de flujo. En la práctica yo no conozco a ninguna que funcione aquí.
  • La pragmática es el uso de una heurística: utilice una herramienta de cobertura de código (en GNU cadena es gcov. Tenga en cuenta que indicadores específicos a los que debe pasar durante la compilación para que funcione correctamente). Ejecutar la herramienta de cobertura de código con un buen conjunto de variadas entradas (su unidad de pruebas o no pruebas de regresión), el código muerto es necesariamente dentro de los no-alcanzados código... y así podemos empezar desde aquí.

Si usted está muy interesado en el tema, y tiene el tiempo y la inclinación a la realidad de trabajo de una herramienta por sí mismo, sugeriría con el Ruido de las bibliotecas para construir una herramienta de este tipo.

  1. Utilice el Ruido de la biblioteca para obtener un AST (abstract syntax tree)
  2. Realizar un mark-and-sweep análisis de los puntos de entrada en adelante

Porque el Ruido se va a analizar el código para usted, y realizar la resolución de sobrecarga, usted no tendrá que lidiar con el C++ lenguajes de reglas, y usted será capaz de concentrarse en el problema en cuestión.

Sin embargo, este tipo de técnica no se puede identificar el virtual reemplaza que no se están utilizando, ya que podría ser llamado por el código de terceros que no se puede razonar sobre.

36voto

olsner Puntos 546

Para el caso de que no se utilicen toda funciones (y sin usar variables globales), GCC, en realidad puede hacer la mayor parte del trabajo para usted, siempre que usted está utilizando GCC y GNU ld.

Al compilar el código fuente, use -ffunction-sections y -fdata-sections, luego al vincular el uso -Wl,--gc-sections,--print-gc-sections. El enlazador aparecerá una lista con todas las funciones que pueden ser eliminadas, porque nunca fueron llamados y todos los globales que nunca se hace referencia.

(Por supuesto, también se puede omitir el --print-gc-sections parte y dejar que el enlazador quitar las funciones de forma silenciosa, pero mantenerlos en la fuente.)

Nota: esto sólo va a encontrar no utilizados completa de funciones, no hacer nada acerca de código muerto dentro de funciones. Funciones de llamada de los muertos código en funciones en vivo también se mantuvo alrededor.

Un poco de C++-características específicas también causa problemas, en particular:

  • Las funciones virtuales. Sin saber que subclases existen y que en realidad son una instancia en tiempo de ejecución, no se puede saber que las funciones virtuales que deben existir en el programa final. El vinculador no tiene suficiente información acerca de que lo que habrá que mantener todos ellos alrededor.
  • Globals con los constructores, y sus constructores. En general, el enlazador no puede saber que el constructor de un mundial no tiene efectos secundarios, por lo que debe ejecutar. Obviamente esto significa que el global de la misma también debe ser mantenido.

En ambos casos, cualquier cosa utilizada por una función virtual o global-variable constructor también tiene que estar alrededor.

Una limitación adicional es que si usted está construyendo una biblioteca compartida, la configuración predeterminada en el GCC de exportación de cada una de las funciones de la biblioteca compartida, provocando que sea "utilizado" tan lejos como el enlazador se refiere. Para arreglar que usted necesita para establecer el valor predeterminado para ocultar símbolos en lugar de exportar (usando por ejemplo. -fvisibility=hidden)y, a continuación, seleccione de forma explícita las funciones exportadas que usted necesita para exportar.

26voto

UmmaGumma Puntos 3154

Bien si con g++ puede utilizar este indicador -Wunused

Según documentación:

Advertir cuando una variable no está en uso aparte de su declaración, siempre que una función es declarada estáticos, sino que nunca se define, cada vez que una etiqueta se declarado, pero no se usa, y cada vez que un declaración calcula un resultado que es explícitamente no se utiliza.

http://docs.freebsd.org/info/gcc/gcc.info.Warning_Options.html

Edit: Aquí es útil indicador -Wunreachable-code Según documentación:

Esta opción está pensada para avisar cuando el compilador detecta que al menos toda una línea de código fuente nunca volverá a ser ejecutada, porque de alguna condición nunca se cumple, o porque es después de un procedimiento que nunca se devuelve.

Actualización: he encontrado tema similar Muertos detección de código en el legado de C/C++ project

18voto

Carlos V Puntos 1194

Creo que usted está buscando una cobertura de código de la herramienta. Una herramienta de cobertura de código analizará el de código mientras se ejecuta, y te hará saber que líneas de código se ejecuta y cómo muchas veces, así como los que no lo eran.

Usted podría tratar de darle a este código de fuente abierta herramienta de cobertura de una oportunidad: TestCocoon - herramienta de cobertura de código para C/C++ y C#.

16voto

Justin Morgan Puntos 12853

La verdadera respuesta es: nunca puedes saber con seguridad.

Al menos, para no trivial de los casos, usted no puede estar seguro de que has conseguido todo. Considere el siguiente artículo de Wikipedia sobre inalcanzable código:

double x = sqrt(2);
if (x > 5)
{
  doStuff();
}

Como Wikipedia señala correctamente, un ingenioso compilador puede ser capaz de coger algo como esto. Pero considerar una modificación:

int y;
cin >> y;
double x = sqrt((double)y);

if (x != 0 && x < 1)
{
  doStuff();
}

Se el compilador coger esto? Tal vez. Pero para hacer eso, se necesita hacer más que correr sqrt contra un escalar constante de valor. Tendrá que averiguar que (double)y siempre será un número entero (fácil), y luego entender la matemática rango de sqrt para el conjunto de los números enteros (duro). Un muy sofisticado compilador podría ser capaz de hacer esto para el sqrt función, o para cada función en math.h, o por cualquier fijo de entrada función cuyo dominio se puede averiguar. Esto se pone muy, muy complejo, y la complejidad es, básicamente, ilimitadas. Se pueden añadir capas de sofisticación a su compilador, pero siempre habrá una manera de colarse en algún código que va a ser inalcanzable para cualquier conjunto dado de insumos.

Y luego están los conjuntos de entrada que simplemente nunca se ingresen. De entrada que tendría ningún sentido en la vida real, o sea bloqueada por la lógica de validación en otros lugares. No hay ninguna forma para que el compilador para saber sobre aquellos.

El resultado final de esto es que mientras que las herramientas de software que otros han mencionado que son muy útiles, nunca vas a saber con certeza que ha alcanzado todo lo que a menos que usted vaya a través del código manualmente después. Incluso entonces, nunca vas a estar seguro de que usted no se pierda nada.

La única solución real, en mi humilde opinión, es a ser tan atentos como sea posible, el uso de la automatización a su disposición, refactorizar donde puede, y buscar constantemente maneras de mejorar el código. Por supuesto, es una buena idea hacerlo de todos modos.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X