2009-04-24 8 views
8

¿Qué opinas sobre las funciones de una línea? ¿Es mala? Una ventaja que se me ocurre es que hace que el código sea más completo (si elige un buen nombre para él). Por ejemplo:Funciones de una línea en C?

void addint(Set *S, int n) 
{ 
    (*S)[n/CHAR_SIZE] |= (unsigned char) pow(2, (CHAR_SIZE - 1) - (n % CHAR_SIZE)); 
} 

Una desventaja que se me ocurre es que se ralentiza el código (empujando parámetros para apilar, saltando a una función, apareciendo los parámetros, haciendo la operación, saltar de nuevo al código - y sólo para una línea?)

¿es mejor poner esas líneas en funciones o simplemente ponerlas en el código? Incluso si los usamos solo una vez?

Por cierto, no he encontrado ninguna pregunta al respecto, así que perdónenme si se me hubiera preguntado antes.

+6

¿Estás preocupado por la sobrecarga de llamadas, pero luego llamas a pow para elevar 2 a la potencia de un entero pequeño? ;-p –

+0

¿Cuál podría ser una mejor manera de hacerlo? Me gustaría saber. –

+2

2^x es lo mismo que 2 << x si x es un número entero –

Respuesta

21

¡No le tenga miedo a las funciones de 1 línea!

Muchos programadores parecen tener un bloqueo mental de funciones de 1 línea, no debería.

Si hace que el código sea más claro y más limpio, extraiga la línea en una función.

El rendimiento probablemente no se verá afectado.

Cualquier compilador decente realizado en la última década (y tal vez más) alineará automáticamente una simple función de 1 línea. Además, una línea de C puede corresponder fácilmente a muchas líneas de código de máquina. No debe suponer que incluso en el caso teórico en el que incurre en la sobrecarga total de una llamada a una función, esta sobrecarga es significativa en comparación con su "pequeña línea". Deje que sea significativo para el rendimiento general de su aplicación.

Abstraction Leads to Better Design. (incluso para líneas simples de código)

Las funciones son los componentes principales del código abstracto y compuesto, no deben descuidarse. Si encapsula una sola línea de código detrás de una llamada de función hace que el código sea más legible, hágalo. Incluso en el caso donde la función se llama una vez. Si le parece importante comentar una línea particular de código, es un buen olor a código que podría ser útil mover el código a una función bien nombrada.

Claro, ese código puede ser de 1 línea hoy, pero ¿cuántas formas diferentes de realizar la misma función existen? El código encapsulado dentro de una función puede hacer que sea más fácil ver todas las opciones de diseño disponibles para usted. Tal vez su código de 1 línea se expande en una llamada a un servicio web, tal vez se convierta en una consulta de base de datos, tal vez se vuelva configurable (usando el patrón de estrategia, por ejemplo), quizás quiera cambiar al almacenamiento en caché del valor calculado por su 1- línea. Todas estas opciones son más fáciles de implementar y se tienen más en cuenta cuando se extrae el código de 1 línea en su propia función.

Tal vez su 1 línea debería ser más líneas.

Si tiene un gran bloque de código, puede ser tentador incorporar una gran cantidad de funcionalidades en una sola línea, solo para guardar en pantalla. Cuando migra este código a una función, reduce estas presiones, lo que puede hacer que esté más inclinado a expandir su complejo 1-liner en un código más directo que ocupe varias líneas (lo que probablemente mejore su legibilidad y capacidad de mantenimiento).

0

Si utiliza el código dentro de esa función 3 veces o más, entonces le recomendaría poner eso en una función. Solo para mantenimiento.

5

Si se usa más de una vez, definitivamente conviértalo en una función, y deje que el compilador haga la alineación (posiblemente agregando "en línea" a la definición de la función). (< Consejos habituales sobre la optimización prematura va aquí >)

0

¿Qué idioma? Si te refieres a C, también usaría el calificador inline. En C++, tengo la opción de inline, boost.lamda oy avanzar soporte nativo de C++ 0x para lamdas.

5

Dado que su ejemplo parece estar usando una sintaxis C (++), es posible que desee leer en inline functions, que elimina la sobrecarga de llamar a una función simple. Sin embargo, esta palabra clave es solo una recomendación para el compilador y puede no incluir todas las funciones que marca, y puede elegir alinear funciones no marcadas.

En .NET el JIT aplicará los métodos que considere apropiados, pero no tiene control sobre por qué o cuándo lo hace, aunque (según tengo entendido) las compilaciones de depuración nunca se alinearán, ya que eso detendría el código fuente haciendo coincidir la aplicación compilada.

8

No soy partidario de tener todo tipo de lógica y funcionalidad golpeadas en una sola línea. El ejemplo que ha mostrado es un desastre y podría dividirse en varias líneas, utilizando nombres de variables significativos y realizando una operación tras otra.

I recomendamos, en cada pregunta de este tipo, para echar un vistazo (comprarlo, pedir prestado, (no) descargarlo (gratis)) en this book: Robert C. Martin - Clean Code. Es un libro que todo desarrollador debería tener en cuenta.

No le hará un buen codificador de inmediato y no le impedirá escribir código feo en el futuro, sin embargo, le hará darse cuenta cuando está escribiendo código feo. Te obligará a mirar tu código con un ojo más crítico y a hacer que tu código sea legible como una historia periodística.

1

No hay nada de malo con las funciones de una línea. Como se mencionó, es posible que el compilador alinee las funciones que eliminarán cualquier penalización de rendimiento.

Las funciones también deben preferirse a las macros, ya que son más fáciles de depurar, modificar, leer y es menos probable que tengan efectos secundarios no deseados.

Si se usa solo una vez, la respuesta es menos obvia.Moverlo a una función puede hacer que la función de llamada sea más simple & más clara al mover parte de la complejidad a la nueva función.

-1

A veces no es una mala idea utilizar el preprocesador:

#define addint(S, n) (*S)[n/CHAR_SIZE] |= (unsigned char) pow(2, (CHAR_SIZE - 1) - (n % CHAR_SIZE)); 

Por supuesto, usted no recibe ningún tipo de comprobación de tipos, pero en algunos casos esto puede ser útil. Las macros tienen sus desventajas y sus ventajas, y en algunos casos sus desventajas pueden convertirse en ventajas. Soy fanático de las macros en lugares apropiados, pero depende de usted decidir cuándo es apropiado. En este caso, me voy a arriesgar y decir que, sea lo que sea que termine haciendo, esa línea de código es bastante amplia.

#define addint(S, n) do { \ 
    unsigned char c = pow(2, (CHAR_SIZE -1) - (n % CHAR_SIZE)); \ 
    (*S)[n/CHAR_SIZE] |= c \ 
    } while(0) 
+2

Quoth el preprocesador: "Abusar de mí, abusa de mí, hazme sentir querido!" –

+1

Simplemente sentí que debería mencionarse para que esté completo. Puede que no sea la mejor solución en este caso, porque no hay verificación de tipo, pero lo menciono. No digo "(ab) usar el preprocesador", digo "no te olvides del preprocesador". No es TAN mala herramienta. –

+0

Acepto que el preprocesador es una herramienta muy útil. Sin embargo, cuando algo se vuelve tan complejo, a menudo es mejor alinearlo, mira el volcado de archivos y ve si tu compilador estuvo de acuerdo. 8/10 veces, el compilador será correcto. Ahora, si su compilador solo está siendo A ** y lo sabe, queda el preprocesador. –