language agnostic - ¿Debería una función tener solo una declaración de retorno?
language-agnostic coding-style (30)
¿Hay buenas razones por las que es mejor tener una sola declaración de devolución en una función?
¿O está bien regresar de una función tan pronto como sea lógicamente correcto hacerlo, lo que significa que puede haber muchas declaraciones de retorno en la función?
¿Hay buenas razones por las que es mejor tener una sola declaración de devolución en una función?
Si hay
- El único punto de salida ofrece un excelente lugar para hacer valer sus post-condiciones.
- Ser capaz de poner un punto de ruptura del depurador en el retorno al final de la función suele ser útil.
- Menos devoluciones significa menos complejidad. El código lineal es generalmente más fácil de entender.
- Si tratar de simplificar una función a un solo retorno causa complejidad, eso es un incentivo para refactorizar funciones más pequeñas, más generales y más fáciles de entender.
- Si está en un idioma sin destructores o si no usa RAII, entonces una sola devolución reduce la cantidad de lugares que tiene que limpiar.
- Algunos idiomas requieren un solo punto de salida (por ejemplo, Pascal y Eiffel).
La pregunta a menudo se plantea como una falsa dicotomía entre declaraciones múltiples o declaraciones profundamente anidadas. Casi siempre hay una tercera solución que es muy lineal (sin anidación profunda) con un solo punto de salida.
Actualización : Al parecer, las pautas de MISRA también promueven la salida única .
Para ser claros, no estoy diciendo que siempre sea incorrecto tener múltiples devoluciones. Pero, dadas las soluciones equivalentes, hay muchas buenas razones para preferir una con un solo retorno.
A menudo tengo varias declaraciones al inicio de un método para devolver para situaciones "fáciles". Por ejemplo, esto:
public void DoStuff(Foo foo)
{
if (foo != null)
{
...
}
}
... se puede hacer más legible (IMHO) así:
public void DoStuff(Foo foo)
{
if (foo == null) return;
...
}
Entonces sí, creo que está bien tener múltiples "puntos de salida" de una función / método.
Actualmente estoy trabajando en una base de código donde dos de las personas que trabajan en él se suscriben ciegamente a la teoría del "punto de salida único" y les puedo decir que, por experiencia, es una práctica horrible y horrible. Hace que el código sea extremadamente difícil de mantener y te mostraré por qué.
Con la teoría del "punto de salida único", inevitablemente terminará con un código que se ve así:
function()
{
HRESULT error = S_OK;
if(SUCCEEDED(Operation1()))
{
if(SUCCEEDED(Operation2()))
{
if(SUCCEEDED(Operation3()))
{
if(SUCCEEDED(Operation4()))
{
}
else
{
error = OPERATION4FAILED;
}
}
else
{
error = OPERATION3FAILED;
}
}
else
{
error = OPERATION2FAILED;
}
}
else
{
error = OPERATION1FAILED;
}
return error;
}
Esto no solo hace que el código sea muy difícil de seguir, sino que ahora diga más adelante que necesita volver y agregar una operación entre 1 y 2. Debe sangrar casi toda la función, y buena suerte asegurándose de que Sus condiciones if / else y llaves se combinan correctamente.
Este método hace que el mantenimiento del código sea extremadamente difícil y propenso a errores.
Como Kent Beck señala cuando discute las cláusulas de guardia en los Patrones de implementación, hacer que una rutina tenga un solo punto de entrada y salida ...
"fue para evitar la posible confusión al saltar dentro y fuera de muchos lugares en la misma rutina. Tenía sentido cuando se aplicaba a los programas de lenguaje ensamblador o FORTRAN escritos con gran cantidad de datos globales en los que incluso entender qué declaraciones se ejecutaban era un trabajo arduo. . Con métodos pequeños y en su mayoría datos locales, es innecesariamente conservador ".
Encuentro que una función escrita con cláusulas de guarda es mucho más fácil de seguir que un montón anidado largo de declaraciones if then else
.
Creo que las devoluciones múltiples suelen ser buenas (en el código que escribo en C #). El estilo de retorno único es un remanente de C. Pero probablemente no esté codificando en C.
No hay ninguna ley que requiera un solo punto de salida para un método en todos los lenguajes de programación . Algunas personas insisten en la superioridad de este estilo, y algunas veces lo elevan a una "regla" o "ley", pero esta creencia no está respaldada por ninguna evidencia o investigación.
Más de un estilo de retorno puede ser un mal hábito en el código C, donde los recursos deben ser desasignados explícitamente, pero los lenguajes como Java, C #, Python o JavaScript que tienen construcciones como la recolección automática de basura y bloques de try..finally
and using
blocks in C#), and this argument does not apply - in these languages, it is very uncommon to need centralised manual resource deallocation.
Hay casos donde una sola declaración es más legible, y casos donde no lo es. Vea si reduce el número de líneas de código, aclara la lógica o reduce el número de llaves y sangrías o variables temporales.
Por lo tanto, use tantas devoluciones como se adapte a sus sensibilidades artísticas, porque es un problema de diseño y legibilidad, no técnico.
He hablado de esto en mayor detalle en mi blog .
En general, trato de tener un solo punto de salida de una función. Sin embargo, hay ocasiones en que al hacerlo se termina creando un cuerpo de función más complejo del que es necesario, en cuyo caso es mejor tener múltiples puntos de salida. Realmente tiene que ser una "llamada de juicio" basada en la complejidad resultante, pero el objetivo debe ser el menor número de puntos de salida posibles sin sacrificar la complejidad y la comprensibilidad.
En una función que no tiene efectos secundarios, no hay una buena razón para tener más de una sola devolución y debe escribirlos en un estilo funcional. En un método con efectos secundarios, las cosas son más secuenciales (indexadas en el tiempo), por lo que escribe en un estilo imperativo, utilizando la instrucción return como un comando para detener la ejecución.
En otras palabras, cuando sea posible, favorece este estilo.
return a > 0 ?
positively(a):
negatively(a);
Más allá de esto
if (a > 0)
return positively(a);
else
return negatively(a);
Si te encuentras escribiendo varias capas de condiciones anidadas, probablemente hay una forma de refactorizar eso, por ejemplo, utilizando la lista de predicados. Si encuentra que sus ifs y otros están muy separados sintácticamente, es posible que desee dividirlos en funciones más pequeñas. Un bloque condicional que abarca más de una pantalla llena de texto es difícil de leer.
No hay una regla dura y rápida que se aplique a todos los idiomas. Algo como tener una única declaración de devolución no hará que tu código sea bueno. Pero un buen código tenderá a permitirte escribir tus funciones de esa manera.
Lo he visto en estándares de codificación para C ++ que eran un resguardo de C, como si no tuviera RAII u otra gestión automática de memoria, entonces tiene que limpiar para cada devolución, lo que significa cortar y pegar de la limpieza o un goto (lógicamente lo mismo que ''finalmente'' en los idiomas administrados), los cuales se consideran de mala forma. Si sus prácticas son usar punteros y colecciones inteligentes en C ++ u otro sistema de memoria automático, entonces no hay una razón sólida para ello, y se trata de legibilidad y más de una llamada de juicio.
Me inclino a la idea de que las declaraciones de retorno en medio de la función son malas. Puede usar devoluciones para crear algunas cláusulas de protección en la parte superior de la función y, por supuesto, decirle al compilador qué devolver al final de la función sin problemas, pero las devoluciones en medio de la función pueden ser fáciles de perder y pueden Hacer la función más difícil de interpretar.
Me obligo a usar solo una declaración de return
, ya que en cierto sentido generará el olor del código. Dejame explicar:
function isCorrect($param1, $param2, $param3) {
$toret = false;
if ($param1 != $param2) {
if ($param1 == ($param3 * 2)) {
if ($param2 == ($param3 / 3)) {
$toret = true;
} else {
$error = ''Error 3'';
}
} else {
$error = ''Error 2'';
}
} else {
$error = ''Error 1'';
}
return $toret;
}
(Las condiciones son arbitrarias ...)
Cuantas más condiciones, más grande se vuelve la función, más difícil es leerla. Entonces, si estás en sintonía con el olor del código, te darás cuenta y querrás refactorizar el código. Dos posibles soluciones son:
- Devoluciones multiples
- Refactorización en funciones separadas
Múltiples devoluciones
function isCorrect($param1, $param2, $param3) {
if ($param1 == $param2) { $error = ''Error 1''; return false; }
if ($param1 != ($param3 * 2)) { $error = ''Error 2''; return false; }
if ($param2 != ($param3 / 3)) { $error = ''Error 3''; return false; }
return true;
}
Funciones separadas
function isEqual($param1, $param2) {
return $param1 == $param2;
}
function isDouble($param1, $param2) {
return $param1 == ($param2 * 2);
}
function isThird($param1, $param2) {
return $param1 == ($param2 / 3);
}
function isCorrect($param1, $param2, $param3) {
return !isEqual($param1, $param2)
&& isDouble($param1, $param3)
&& isThird($param2, $param3);
}
Por supuesto, es más largo y un poco desordenado, pero en el proceso de refactorizar la función de esta manera, hemos
- creado una serie de funciones reutilizables,
- Hizo la función más legible para los humanos, y
- El enfoque de las funciones está en por qué los valores son correctos.
Mi preferencia sería por una salida única a menos que realmente complique las cosas. Descubrí que, en algunos casos, los puntos múltiples pueden enmascarar otros problemas de diseño más importantes:
public void DoStuff(Foo foo)
{
if (foo == null) return;
}
Al ver este código, inmediatamente preguntaría:
- ¿Alguna vez es nulo?
- Si es así, ¿cuántos clientes de ''DoStuff'' alguna vez llaman a la función con un ''foo'' nulo?
Dependiendo de las respuestas a estas preguntas puede ser que
- el cheque no tiene sentido ya que nunca es verdadero (es decir, debería ser una aserción)
- la verificación rara vez es verdadera y, por lo tanto, puede ser mejor cambiar esas funciones específicas de la persona que llama, ya que probablemente deberían realizar alguna otra acción de todos modos.
En los dos casos anteriores, el código probablemente se puede volver a trabajar con una aserción para garantizar que ''foo'' nunca sea nulo y que se cambien los llamantes relevantes.
Existen otras dos razones (específicas, creo que para el código C ++), en las que la existencia múltiple puede tener un efecto negativo . Son el tamaño del código, y las optimizaciones del compilador.
Un objeto C ++ no POD en el alcance a la salida de una función tendrá su destructor llamado. Cuando hay varias declaraciones de retorno, puede darse el caso de que haya diferentes objetos en el alcance y, por lo tanto, la lista de destructores a los que llamar será diferente. Por lo tanto, el compilador necesita generar código para cada declaración de retorno:
void foo (int i, int j) {
A a;
if (i > 0) {
B b;
return ; // Call dtor for ''b'' followed by ''a''
}
if (i == j) {
C c;
B b;
return ; // Call dtor for ''b'', ''c'' and then ''a''
}
return ''a'' // Call dtor for ''a''
}
Si el tamaño del código es un problema, entonces esto puede ser algo que vale la pena evitar.
El otro problema se relaciona con la "Optimización de valor de retorno con nombre" (también conocido como Copy Elision, ISO C ++ ''03 12.8 / 15). C ++ permite que una implementación omita llamar al constructor de copia si puede:
A foo () {
A a1;
// do something
return a1;
}
void bar () {
A a2 ( foo() );
}
Simplemente tomando el código como está, el objeto ''a1'' se construye en ''foo'' y luego su construcción de copia se llamará para construir ''a2''. Sin embargo, copy elision permite al compilador construir ''a1'' en el mismo lugar en la pila que ''a2''. Por lo tanto, no hay necesidad de "copiar" el objeto cuando la función regresa.
Los puntos de salida múltiples complican el trabajo del compilador al tratar de detectar esto, y al menos para una versión relativamente reciente de VC ++, la optimización no tuvo lugar donde el cuerpo de la función tuvo múltiples retornos. Consulte la Optimización del valor de retorno con nombre en Visual C ++ 2005 para obtener más detalles.
Nadie ha mencionado o citado el Código Completo, así que lo haré.
17.1 retorno
Minimiza el número de devoluciones en cada rutina . Es más difícil entender una rutina si, al leerla en la parte inferior, desconoce la posibilidad de que haya regresado a algún lugar arriba.
Utilice una devolución cuando mejora la legibilidad . En ciertas rutinas, una vez que sepa la respuesta, querrá volver a la rutina de llamada inmediatamente. Si la rutina se define de tal manera que no requiere ninguna limpieza, no volver inmediatamente significa que tiene que escribir más código.
No, porque ya no vivimos en la década de 1970 . Si su función es lo suficientemente larga como para que las devoluciones múltiples sean un problema, es demasiado larga.
(Aparte del hecho de que cualquier función multilínea en un idioma con excepciones tendrá múltiples puntos de salida de todos modos).
Tener un solo punto de salida proporciona una ventaja en la depuración, porque le permite establecer un único punto de interrupción al final de una función para ver qué valor realmente se va a devolver.
Tener un solo punto de salida reduce la Complejidad ciclomática y, por lo tanto, en teoría , reduce la probabilidad de que introduzcas errores en tu código cuando lo cambies. Sin embargo, la práctica tiende a sugerir que se necesita un enfoque más pragmático. Por lo tanto, tiendo a apuntar a tener un solo punto de salida, pero permito que mi código tenga varios si es más legible.
Yo diría que debería tener tantos como se requiera, o cualquiera que haga que el código sea más limpio (como las cláusulas de protección ).
Personalmente nunca he escuchado / visto ninguna "mejor práctica" que diga que usted debería tener solo una declaración de devolución.
En su mayor parte, tiendo a salir de una función tan pronto como sea posible en base a una ruta lógica (las cláusulas de guarda son un excelente ejemplo de esto).
Yo diría que sería increíblemente imprudente decidir arbitrariamente contra múltiples puntos de salida, ya que he encontrado que la técnica es útil en la práctica una y otra vez , de hecho, a menudo he refaccionado el código existente con múltiples puntos de salida para mayor claridad. Podemos comparar los dos enfoques de esta manera:
string fooBar(string s, int? i) {
string ret = "";
if(!string.IsNullOrEmpty(s) && i != null) {
var res = someFunction(s, i);
bool passed = true;
foreach(var r in res) {
if(!r.Passed) {
passed = false;
break;
}
}
if(passed) {
// Rest of code...
}
}
return ret;
}
Compare esto con el código donde se permiten múltiples puntos de salida: -
string fooBar(string s, int? i) {
var ret = "";
if(string.IsNullOrEmpty(s) || i == null) return null;
var res = someFunction(s, i);
foreach(var r in res) {
if(!r.Passed) return null;
}
// Rest of code...
return ret;
}
Creo que este último es considerablemente más claro. Por lo que puedo decir, la crítica de múltiples puntos de salida es un punto de vista bastante arcaico en estos días.
La programación estructurada dice que solo debería tener una declaración de retorno por función. Esto es para limitar la complejidad. Muchas personas, como Martin Fowler, argumentan que es más sencillo escribir funciones con múltiples declaraciones de retorno. Presenta este argumento en el clásico libro de refactoring que escribió. Esto funciona bien si sigues sus otros consejos y escribes pequeñas funciones. Estoy de acuerdo con este punto de vista y solo los puristas de la programación estructurada estricta se adhieren a las declaraciones de retorno individuales por función.
Esta es probablemente una perspectiva inusual, pero creo que cualquiera que crea que se deben favorecer varias declaraciones de devolución nunca ha tenido que usar un depurador en un microprocesador que admite solo 4 puntos de interrupción de hardware. ;-)
Si bien los problemas del "código de flecha" son completamente correctos, un problema que parece desaparecer cuando se usan varias declaraciones de retorno es en la situación en la que está utilizando un depurador. No tiene una posición de captura para todos conveniente para establecer un punto de interrupción para garantizar que verá la salida y, por lo tanto, la condición de retorno.
He trabajado con terribles estándares de codificación que forzaron una única ruta de salida en ti y el resultado es casi siempre un espagueti desestructurado si la función es trivial: terminas con muchos descansos y continúa, y eso simplemente interfiere.
Cuantas más declaraciones de devolución tenga en una función, mayor será la complejidad en ese método. Si se pregunta si tiene demasiadas declaraciones de devolución, es posible que desee preguntarse si tiene demasiadas líneas de código en esa función.
Pero, no, no hay nada malo con una / muchas declaraciones de devolución. En algunos idiomas, es una práctica mejor (C ++) que en otros (C).
El único punto de salida (todo lo demás igual) hace que el código sea mucho más legible. Pero hay una trampa: la construcción popular.
resulttype res;
if if if...
return res;
es falso, "res =" no es mucho mejor que "return". Tiene una única declaración de retorno, pero múltiples puntos donde la función realmente termina.
Si tiene una función con múltiples retornos (o "res =" s), a menudo es una buena idea dividirla en varias funciones más pequeñas con un solo punto de salida.
Hay cosas buenas que decir acerca de tener un solo punto de salida, al igual que hay cosas malas que decir acerca de la inevitable "arrow" programación que resulta.
Si utilizo varios puntos de salida durante la validación de entrada o la asignación de recursos, trato de poner todas las ''salidas de error'' muy visibles en la parte superior de la función.
Tanto el artículo de Programación Spartan de "SSDSLPedia" como el artículo de punto de salida de función única de "Portland Pattern Repository''s Wiki" tienen algunos argumentos perspicaces al respecto. Además, por supuesto, hay que tener en cuenta esta publicación.
Si realmente desea un solo punto de salida (en cualquier lenguaje no habilitado para excepciones), por ejemplo, para liberar recursos en un solo lugar, encuentro que la aplicación cuidadosa de goto es buena; Vea, por ejemplo, este ejemplo bastante artificial (comprimido para guardar la pantalla de bienes raíces):
int f(int y) {
int value = -1;
void *data = NULL;
if (y < 0)
goto clean;
if ((data = malloc(123)) == NULL)
goto clean;
/* More code */
value = 1;
clean:
free(data);
return value;
}
Personalmente, a mí, en general, no me gusta la programación de flechas más de lo que no me gustan los puntos de salida múltiples, aunque ambos son útiles cuando se aplican correctamente. Lo mejor, por supuesto, es estructurar su programa para que no requiera ninguno. Desglosar su función en múltiples partes por lo general ayuda :)
Aunque al hacerlo, encuentro que al final tengo múltiples puntos de salida como en este ejemplo, donde una función más grande se ha dividido en varias funciones más pequeñas:
int g(int y) {
value = 0;
if ((value = g0(y, value)) == -1)
return -1;
if ((value = g1(y, value)) == -1)
return -1;
return g2(y, value);
}
Dependiendo del proyecto o las directrices de codificación, la mayoría del código de la placa de la caldera podría ser reemplazado por macros. Como nota al margen, descomponerlo de esta manera hace que las funciones g0, g1, g2 sean muy fáciles de probar individualmente.
Obviamente, en un OO y un lenguaje habilitado para excepciones, no usaría sentencias if (o, en absoluto, si pudiera hacerlo con el menor esfuerzo), y el código sería mucho más sencillo. Y no-arrowy. Y la mayoría de las devoluciones no finales probablemente serían excepciones.
En breve;
- Pocos retornos son mejores que muchos retornos.
- Más de un retorno es mejor que las flechas gigantes, y las cláusulas de guardia generalmente están bien.
- Las excepciones podrían / deberían reemplazar la mayoría de las "cláusulas de protección" cuando sea posible.
Los puntos de salida múltiples están bien para funciones suficientemente pequeñas, es decir, una función que se puede ver en una pantalla en su totalidad. Si una función larga también incluye múltiples puntos de salida, es una señal de que la función se puede recortar aún más.
Dicho esto, evito las funciones de salida múltiple a menos que sea absolutamente necesario . He sentido el dolor de los errores que se deben a algún retorno perdido en alguna línea oscura en funciones más complejas.
Me inclino por usar cláusulas de guardia para regresar temprano y, de lo contrario, salir al final de un método. La única regla de entrada y salida tiene un significado histórico y fue particularmente útil al tratar con el código heredado que se extendía a 10 páginas A4 para un solo método C ++ con múltiples devoluciones (y muchos defectos). Más recientemente, la buena práctica aceptada es mantener los métodos pequeños, lo que hace que las salidas múltiples sean menos que una impedancia para la comprensión. En el siguiente ejemplo de Kronoz copiado desde arriba, la pregunta es qué ocurre en // ¿Resto del código ... ?
void string fooBar(string s, int? i) {
if(string.IsNullOrEmpty(s) || i == null) return null;
var res = someFunction(s, i);
foreach(var r in res) {
if(!r.Passed) return null;
}
// Rest of code...
return ret;
}
Me doy cuenta de que el ejemplo es algo artificial, pero estaría tentado de refactorizar el bucle foreach en una declaración LINQ que luego podría considerarse una cláusula de seguridad. Una vez más, en un ejemplo artificial la intención del código no es aparente y someFunction () puede tener algún otro efecto secundario o el resultado puede ser utilizado en la // Resto del código ... .
if (string.IsNullOrEmpty(s) || i == null) return null;
if (someFunction(s, i).Any(r => !r.Passed)) return null;
Dando la siguiente función refactorizada:
void string fooBar(string s, int? i) {
if (string.IsNullOrEmpty(s) || i == null) return null;
if (someFunction(s, i).Any(r => !r.Passed)) return null;
// Rest of code...
return ret;
}
Mi política habitual es tener solo una declaración de retorno al final de una función a menos que la complejidad del código se reduzca considerablemente al agregar más. De hecho, soy más bien un fanático de Eiffel, que impone la única regla de devolución al no tener una declaración de devolución (solo hay una variable ''resultado'' creada automáticamente que incluye su resultado)
Ciertamente, hay casos en que el código puede ser más claro con múltiples devoluciones de lo que sería la versión obvia sin ellos. Se podría argumentar que es necesario volver a trabajar más si tiene una función que es demasiado compleja para ser comprensible sin múltiples declaraciones de devolución, pero a veces es bueno ser pragmático sobre tales cosas.
Sabes el adagio: la belleza está en los ojos del espectador .
Algunas personas confían en NetBeans y otras en IntelliJ IDEA , otras en Python y otras en PHP .
En algunas tiendas podrías perder tu trabajo si insistes en hacer esto:
public void hello()
{
if (....)
{
....
}
}
La pregunta es todo acerca de la visibilidad y el mantenimiento.
Soy adicto al uso del álgebra booleana para reducir y simplificar la lógica y el uso de las máquinas de estado. Sin embargo, hubo colegas anteriores que creyeron que mi empleo de "técnicas matemáticas" en la codificación no es adecuado, porque no sería visible y mantenible. Y eso sería una mala práctica. Lo siento, las técnicas que utilizo son muy visibles y mantenibles para mí, porque cuando regrese al código seis meses después, entendería el código claramente y no vería un lío de espaguetis proverbiales.
Hola amigo (como solía decir un cliente anterior) haz lo que quieras siempre que sepas cómo solucionarlo cuando necesito que lo arregles.
Recuerdo que hace 20 años, un colega mío fue despedido por emplear lo que hoy se llamaría estrategia de desarrollo ágil . Tenía un plan incremental meticuloso. Pero su gerente le estaba gritando: "¡No puedes liberar las funciones a los usuarios de manera gradual! Debes seguir con la waterfall ". Su respuesta al gerente fue que el desarrollo incremental sería más preciso para las necesidades del cliente. Él creía en el desarrollo para las necesidades de los clientes, pero el gerente creía en la codificación según el "requisito del cliente".
Frecuentemente somos culpables por romper la normalización de datos, MVP y MVC . Estamos en línea en lugar de construir una función. Tomamos atajos.
Personalmente, creo que PHP es una mala práctica, pero que sé yo. Todos los argumentos teóricos se reducen a tratar de cumplir un conjunto de reglas.
Calidad = precisión, mantenibilidad y rentabilidad.
Todas las demás reglas se desvanecen en el fondo. Y, por supuesto, esta regla nunca se desvanece:
La pereza es la virtud de un buen programador.
Si terminas con más de unas pocas devoluciones, puede que haya algún error con tu código. De lo contrario, estaría de acuerdo en que a veces es bueno poder regresar de varios lugares en una subrutina, especialmente cuando el código está más limpio.
Perl 6: mal ejemplo
sub Int_to_String( Int i ){
given( i ){
when 0 { return "zero" }
when 1 { return "one" }
when 2 { return "two" }
when 3 { return "three" }
when 4 { return "four" }
...
default { return undef }
}
}
sería mejor escrito así
Perl 6: buen ejemplo
@Int_to_String = qw{
zero
one
two
three
four
...
}
sub Int_to_String( Int i ){
return undef if i < 0;
return undef unless i < @Int_to_String.length;
return @Int_to_String[i]
}
Note que esto fue solo un ejemplo rápido.
Una buena razón que se me ocurre es para el mantenimiento del código: tiene un solo punto de salida. Si desea cambiar el formato del resultado, ..., es mucho más sencillo de implementar. Además, para la depuración, puede pegar un punto de interrupción allí :)
Habiendo dicho eso, una vez tuve que trabajar en una biblioteca donde los estándares de codificación impusieron ''una declaración de retorno por función'', y me pareció bastante difícil. Escribo muchos códigos de cálculo numérico y, a menudo, hay "casos especiales", por lo que el código terminó siendo bastante difícil de seguir ...
Yo voto por la devolución individual al final como guía. Esto ayuda a un manejo de limpieza de código común ... Por ejemplo, eche un vistazo al siguiente código ...
void ProcessMyFile (char *szFileName)
{
FILE *fp = NULL;
char *pbyBuffer = NULL:
do {
fp = fopen (szFileName, "r");
if (NULL == fp) {
break;
}
pbyBuffer = malloc (__SOME__SIZE___);
if (NULL == pbyBuffer) {
break;
}
/*** Do some processing with file ***/
} while (0);
if (pbyBuffer) {
free (pbyBuffer);
}
if (fp) {
fclose (fp);
}
}