lunes, 1 de junio de 2009

EFICIENCIA Y PORTABILIDAD EN EL C

La capacidad dé escribir programas que utilicen con eficiencia los recursos del sistema, estén libres de errores (error-free) y sean fácilmente transportables a otros computadores son los signos que indican el paso de un buen programador y el uso de un lenguaje adecuado.

EFICIENCIA

Cuando hablamos de eficiencia en un programa de ordenador nos referimos tanto a su velocidad de ejecuciòn como a la utilizaciòn òptima de los recursos crìticos del sistema (memoria y ocupaciòn en disco, basicamente). No basta con que los programas funcionen, sino que además deben hacerlo de manera que supongan la menor carga posible para el ordenador y no gasten sus recursos inútilmente.

Normalmente, la optimización de uñ aspecto del programa suele degradar otros. Por ejemplo, hacer que un programa se ejecute más rápido normalmente requiere que se duplique el código fuente en algunos casos, en lugar de realizar llamadas a funciones. También se puede conseguir un ahorro de ocupación en disco, utilizando empaquetado de datos, a costa de degradar la velocidad de acceso a los datos. Estas y otras posibilidades de mejora de la eficiencia pueden ser frustrantes para los no-programadores, a quienes les puede costar comprender cómo la mejora de una característica de un programa puede afectar negativamente a otras, llegando incluso a empeorar el resultado final.

Afortunadamente, existen algunas técnicas de programación que mejoran siempre la eficiencia en cualquier sistema que consideremos.

Por ejemplo, el uso de operadores de incremento ++ y decremento — es más rápido y compacto que la utilización de operaciones como x = x + 1 (frente a x++).

La utilización de funciones puede resultar perjudicial en ocasiones, como es en el caso de una función que sea llamada desde el interior de un bucle un gran número de veces. Pensemos en el siguiente ejemplo:

/* Función que evalúa el valor del polinomio

* x + 3x -1 en el intervalo de valores de O a 100

*/

for (i =0; i <>

x = polin((double) i);

printf < " d f n" , i , x > ;

double polin(z)

double z;

return <

Sería más eficiente la escritura del programa en la forma:

for (i =0; i <>

x = (double) i;

x = ( (x + 3) * x -1) ;

printf <" d f n", i , x) ;

}

donde hemos eliminado la llamada a la función polin, que debería realizarse 100 veces, con lo que esto significa en cuanto a secuencias de llamada y retorno de función y manejo de stack: la llamada requiere salvar el estado de determinados registros de la CPU mediante la instrucción push de ensamblador, y el retorno requiere la recuperación de sus valores briginales mediante la instrucción pop; en ocasiones la función exige además la utilización de variables automáticas que han de ser definidas en cada llamada a función.

La utilización de punteros en lugar de índices de arrays genera un código más compacto en todos los casos, si tenemos en cuenta que internamente el compilador convierte todas las referencias a subíndices en manejo de punteros.

Por ejemplo accedería al elemento "j" del array creando internamente un puntero al elemento 0 del array y desplazando el puntero en "j" elementos, incrementando posteriormente "j" en 1.

Sería más eficiente porque "p" ya es directamente un puntero al elemento "j" del array al que deseamos acceder. El manejo de punteros es muy utilizado en los casos en que se desea acceder secuencialmente a todos los elejnentos de un array.

En algunos círculos C es considerado como un lenguaje críp-tico, difícil de leer y de escribir. Esta mala reputación es debida Integramente al estilo de algunos programadores, amigos de escribir programas difíciles de comprender incluso para ellos mismos cuando ha transcurrido algún tiempo desde su escritura, debido a la utilización de nombres de variables inadecuados, problemas muy complejos llenos de "trucos" y utilización de expresiones complicadas en la misma línea sin hacer uso de variables intermedias. Todo esto puede.hacer en ocasiones que los programas sean un poco más rápidos, al precio de hacerlos ininteligibles, siendo más razonable plantearse de antemano la idea de si no sería posible mejorar el algoritmo empleado, reducir el núme-i o de llamadas a funciones o, en casos muy extremos, codificar alguna subrutina en lenguaje ensamblador, aunque esto requiere una muy buena razón para hacerlo.

No hay comentarios:

Publicar un comentario