¿Cuál es la mejor manera de dividir una función C muy grande con alrededor de 50 variables locales en funciones más pequeñas?

Tengo una función C de 3500 líneas escrita por otra persona que necesito dividirla sin causar ninguna regresión. Como está en C, el principal problema al que me enfrento es mantener el estado de las variables. Por ejemplo, si divido una pequeña parte del código en otra función, tendré que pasar 10 argumentos. Algunos de ellos cambiarán realmente dentro del código de la nueva función. Tan efectivamente tendré que pasarles un puntero. Se vuelve muy desordenado. ¿Hay una mejor manera de lidiar con tal refactorización? ¿Alguna "mejor práctica"?

preguntado el 22 de mayo de 12 a las 20:05

¿Una función larga de 3500 líneas? Apuesto a que todo lo que hace es imprimir "Hello World"... -

Use una estructura (puntero a) para empaquetar variables por argumento. Supongo que una función tan grande hará muchas cosas fáciles de dividir por "tema":

"escrito por otra persona que necesito romper". Te siento .) -

¿Por qué necesitas separarlo? El autor original puede haber tenido una buena razón para convertirlo en una gran función. -

"Tengo una función C de 3500 líneas escrita por otra persona que necesito dividirla sin causar ninguna regresión". : ¿Puedes transformarte en otra persona?-) -- Si una función no está escrita razonablemente inicialmente, puede ser difícil reescribirlo con una mejor estructura. Con bastante frecuencia, es mejor comenzar con solo una descripción de lo que se supone que debe hacer y una hoja de papel en blanco, y recrear todo desde cero. -

6 Respuestas

Examen de la unidad. Extrae pequeñas porciones del código que dependen de 3 variables o menos (1 variable mejor) y pruébalo. Reemplace ese código en la función original con una llamada a la nueva función.

contestado el 22 de mayo de 12 a las 20:05

  • Cada función debe hacer una cosa que sea fácil de descifrar al examinar el código.
  • En lugar de pasar 10 variables, colóquelas en una estructura y pásela.

contestado el 22 de mayo de 12 a las 20:05

En mi opinión, lo mejor que puede hacer es estudiar a fondo esa función y comprender completamente su funcionamiento interno. Es más que probable que esta función tenga muchos antipatrones en su interior, por lo que no intentaría refactorizarla: una vez que supiera cómo funciona (que entiendo que esto puede suponer mucho tiempo) la tiraría y reescriba las funciones más pequeñas equivalentes necesarias, desde cero.

contestado el 22 de mayo de 12 a las 20:05

¿Empaquetar las variables locales que se comparten entre varias de las subfunciones en una estructura y entregar la estructura?

contestado el 22 de mayo de 12 a las 20:05

¿Estás atascado con C? A veces he convertido tales funciones en una clase de C++, donde convierto algunas (o todas) las variables locales en variables miembro. Una vez que se haya realizado este paso, puede dividir fácilmente parte del código en métodos que funcionen en las variables miembro.

En la práctica esto significa que una función como:

... do_xxx(...)
{
  .. some thousand lines of code...
}

se puede convertir en:

class xxx_handler
{
public:
  xxx_handler(...);
  ... run(...)
  {
    part1();
    part2();
    part3();
    return ...;
  }
private:
  // Member variables goes here.
};

// New replacement function.
... do_xxx(...)
{
  xxx_handler handler(...);
  return handler.run(...);
}

contestado el 22 de mayo de 12 a las 20:05

C ++ no hace absolutamente nada para ayudar al OP a comprender el código y determinar lugares lógicos para dividirlo en funciones más pequeñas. Y convertir a los locales en miembros de la clase es probablemente un paso en la dirección equivocada, solo un poco mejor que convertir a los locales en globales. - Brian MacFarland

@BrianMcFarland, ¡debo estar en desacuerdo! La orientación a objetos es una herramienta poderosa. La mayoría de la gente solo lo usa para modelar. large sistemas, pero funciona sorprendentemente bien para chica sistemas, como los que a veces se escriben como funciones enormes. Al convertir funciones enormes al formato orientado a objetos que describí anteriormente, queda claro qué variables locales deben permanecer locales en funciones más pequeñas (por ejemplo, variables temporales y contadores de bucle) y cuáles realmente contienen información global de funciones, cuáles son las que se convierten. a las variables miembro. Su comparación con los globales es defectuosa de varias maneras... - lindybailarina

Una cosa para empezar, como primer paso para sacar partes de la función como funciones independientes, es mover las variables temporales de "función global" para que estén en un alcance más estricto, algo así como:

int temp;

temp = 5;
while(temp > 0) {...}
... 
temp = open(...);
if (temp < 0) {...}

convertido a

{
  int temp = 5;
  while(temp > 0) {...}
}
...
{
  int temp = open(...);
  if (temp < 0) {...}
}

Después de eso, es más fácil mover cada {} bloque en una función separada, que hace una cosa bien definida.

Pero luego, la pauta más importante después de tener pruebas unitarias: use el control de versiones que admite "selección de cerezas" (como git). Cometer a menudo, básicamente cada vez que se compila después de refactorizar algo, luego se vuelve a confirmar (o enmendar la confirmación anterior si no desea tener la primera versión de confirmación) cuando realmente funciona. Aprenda a usar la herramienta de diferenciación del control de versiones y a la selección selectiva cuando necesite retroceder después de romper algo.

respondido 23 nov., 12:11

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.