Curso de programación PIC en C con CCS. Funciones (1)

Volver al índice

 

Las funciones son el pilar de los lenguajes estructurados como es el C, cualquier programa medianamente grande debe de estar formado por diferentes funciones, cada una de ellas hará una tarea determinada y serán llamadas desde la función principal (main) o desde otras funciones según vayan haciendo falta a lo largo de la ejecución del programa, por tanto es de vital importancia el conocer a fondo todas sus posibilidades, no solo para construir nuestras propias funciones, sino también para entender el código de programas y librerías hechos por otras personas.

Vamos ha empezar con algunas definiciones y ejemplos sencillos aplicados al compilador CCS.

1. INTRODUCCIÓN

  • Las funciones son los elementos principales de un programa en C.
  • Son bloques en los cuales se realiza una tarea específica.
  • Un programa en C está formado por la función main que es el bloque principal, por funciones propias del programador y por funciones de librerías propias del compilador.
  • Una característica importante de las funciones, es que pueden recibir parámetros y que pueden devolver un valor. La misma función nos puede servir para varios casos, con tan solo variar el valor de los parámetros. El compilador de CCS incluye muchas funciones "built-in" (listas para usarse) en sus librerías para el control directo de muchos de los recursos del PIC, para utilizarlas sólo necesitamos saber los parámetros que reciben y los valores que devuelven.

2. PARTES DE UNA FUNCIÓN

En una función hay que distinguir tres partes:

  • La declaración (también denominada prototipo).
  • La definición (o la propia función).
  • La llamada a la función.

El hecho de que nuestro programa defina una función, no quiere decir que esa función sea ejecutada. A menos que se produzca una llamada a la función, la función no será ejecutada, sino tan solo definida.

Por ejemplo, cuando nosotros incluimos la directiva #USE RS232 que es una directiva asociada a las bibliotecas precompiladas, incluimos los prototipos de muchas funciones, pero sólo se ejecutan aquellas funciones a las que llamamos, como printf. Vamos a ver con más detalle cada una de estas partes.

2.1 Declaración de una función

  • La declaración de una función se denomina prototipo de la función.
  • El prototipo aparece antes del bloque main, o normalmente en los archivos de cabecera (.h)
  • El prototipo de una función debe aparecer antes de su llamada, y le indica al compilador el número de parámetros que utiliza una función, y de que tipo son.

La sintaxis del prototipo es:

tipo nombre_función(parámetros);  

Donde:

tipo-> es el tipo de dato que va a devolver la función. Si no se indica ningún tipo de dato, por defecto
se asume el tipo int. Si la función no va a devolver ningún dato hay que poner void.

nombre_funcion-> es el identificador de la función, con el que va a ser referenciada.


parámetros-> es la lista de parámetros (valores) que recibe la función; en la declaración también sería  
correcto la siguiente expresión:

tipo nombre_función(tipo,tipo, tipo,....);

En el cual tenemos tantos tipos como parámetros vaya a aceptar la función.

Supongamos una función que define un parámetro de tipo float y que cuando es llamada en el programa, se le pasa un dato de tipo int. Como en el prototipo se ha indicado que el parámetro es de tipo float, el compilador convertirá primero el dato de tipo int a float, y después le pasará como parámetro a la función ese dato convertido.

La declaración de la función también controla que el número de argumentos usados en una llamada a una función coincida con el número de parámetros de la definición.

2.2 Definición de una función

La definición es la función en sí, el bloque de sentencias que va a componer esa función. La sintaxis
de la definición de una función es:

tipo nombre_función(parámetros)
{
declaración de datos de la función.
cuerpo de la función
}

La función va encabezada por el prototipo, pero esta vez sin finalizar en punto y coma. Después, se
incluye el bloque de sentencias de la función.

La lista de parámetros puede ser vacía, sin parámetros, si bien los paréntesis de la función deben
colocarse de igual forma.

Las definiciones de las funciones es aconsejable escribirlas a continuación de la función main()

Un ejemplo de la definición de una función sería:

float division (float x, float y)
{
float resultado;
resultado=x/y;
return(resultado)
}

Nota: Una función C, no puede contener en su interior otras funciones.

2.3 Llamada a una función

Para ejecutar una función hay que llamarla. La llamada a una función consta del nombre de la misma
y de una lista de argumentos o valores a pasar denominados parámetros actuales, separados por comas y encerrados entre paréntesis.

Cuando el programa llama a una función, la ejecución del programa se transfiere a dicha función. El  
programa retorna a la sentencia posterior a la llamada cuando acaba esa función. La sintaxis de una
llamada a una función es:

nombre(parámetros);

donde:

nombre-> es el identificador con que es definida la función a la que queremos llamar.
parámetros-> es la lista de valores que se asignan a cada parámetro de la función (en caso de que  
tenga), separados también por comas.

3. VALORES DEVUELTOS

Todas las funciones, excepto aquellas de tipo void, devuelven un valor. Este valor se especifica
explícitamente en la sentencia return y si no existe ésta, el valor es 0.

La forma general de return es:

return expresión;

Tres observaciones sobre la sentencia return:

A) La sentencia return tiene dos usos importantes. Primero, fuerza a una salida inmediata de la
función, esto es, no espera a que se llegue a la última sentencia de la función para acabar.
Segundo, se puede utilizar para devolver un valor.

B) return no es una función sino una palabra clave del C, por lo tanto no necesita paréntesis
como las funciones, aunque también es correcto: return(expresión); pero teniendo en cuenta
que los paréntesis forman parte de la expresión, no representa una llamada a una función.

C) En las funciones de tipo void se puede hacer:  

return;

y de esta forma se provoca la salida inmediata de la función.

La función (como hemos dicho, en realidad es una sentencia de C) admite cualquier expresión
valida en C.

Ejemplo.

int multiplica (int x, int y)
{

return (x*y);

}

Si el tipo de datos de la expresión de la sentencia return no coincide con el tipo de datos que debe devolver la función automáticamente se convierte el tipo de datos para que haya coincidencia.   

Una función puede contener varias sentencias return() en su código.

Ejemplo.

int compara (int x, int y)

{
if(x<y)
return (0);
else
return (1);
}

Todas las funciones pueden devolver variables de cualquiera de los tipos de datos válidos en C.

Si no se especifica el tipo, la función por defecto devuelve un entero.

Por ejemplo, las siguientes funciones son equivalentes:

 

int resta (int x, int y)

{                                    
int z;                              
z = y-x;                                      
return (z);

}

resta (int x, int y)               
{                                    
int z;                                
z = y-x;                                              
return (z);                            
}



Una función que devuelva un tipo de datos válido en C se puede usar como operando en cualquier
expresión válida en C.

Ejemplo.

int resultado;
resultado = resta(4,6)*10;

Una función no puede usarse a la izquierda de una asignación.

Ejemplo.

resta(a,b)=12; //Esta asignación es incorrecta

El valor devuelto por una función en la sentencia return() puede no ser usado en una asignación,
ni en una expresión válida en C, con lo cual este valor devuelto se perderá.

En otras palabras, aunque todas las funciones, excepto las declaradas como void, devuelven valores,
no se tiene que usar necesariamente ese valor de vuelta para algo.
Una pregunta muy común acerca de los valores devueltos por una función es: ¿ya que se devuelve un
valor?, ¿no se tiene que asignar ese valor de vuelta a alguna variable? . La respuesta es no. Si no
hay una asignación especificada, el valor devuelto simplemente  se ignora.

Vamos a ver algunos ejemplos sencillos de utilización de funciones:


 /*Ejemplo de una función que devuelve un valor de tipo entero y que no tiene parámetros*/ 
 
#include <16F877A.h> 
#FUSES NOWDT, XT, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, WRT_50% 
#use delay(clock=4000000) 
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8) 
 
int producto();  /*Prototipo de la función*/ 
 
void main() { 
 
 int resultado; 
 resultado=producto();   /*llamada a la función producto*/ 
 printf("El resultado de x*y es:  %d\r",resultado); 
 
} 
 
/*DEFINICIÓN DE LA FUNCION*/ 
 
 int producto() 
 {   
 int x=4; 
 int y=5; 
 int producto; 
 printf("El valor de x=4\r"); 
 printf("El valor de y=5\r"); 
 producto=x*y; 
 return(producto);//La función se ejecuta y devuelve el valor de la variable producto después el programa continua en la función main, en la sentencia siguiente a la llamada de la función.
}

Si simulamos el ejemplo con Proteus obtendremos obtendremos la siguiente salida en la terminal:

 

Ejemplo1

 

En el siguiente ejemplo se muestra diferentes formas de usar el valor devuelto por una función:


#include <16F877A.h> 
#FUSES NOWDT, XT, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, WRT_50% 
#use delay(clock=4000000) 
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8) 
 
 multiplica(int a, int b);//declaración de la función 
 void main(void) 
 { 
 int x,y,z; 
 x=5; 
 y=4; 
 z=multiplica (x,y); //en esta línea el valor de vuelta de multiplica() es asignado a z 
 printf("%d",multiplica(x,y)); //en esta, el valor de vuelta no se asigna, sino que se usa en la función printf 
 multiplica (x,y);  //aquí el valor de vuelta se pierde porque no se asigna a otra variable ni se usa como parte de una expresión.       
 } 
 
 //Definición de la función 
 multiplica (int a, int b) 
 
 { 
 return a*b; 
 
 } 


 

En el siguiente ejemplo se muestra lo que ocurre cuando no hay coincidencia en el número de parámetros declarados en el prototipo con el número de argumentos en la llamada a la función.

 

//Este programa no compilará porque no coincide el número de parámetros especificados en el prototipo de la función con el número de argumentos usados en la llamada 
 
#include <16F877A.h> 
#FUSES NOWDT, XT, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, WRT_50% 
#use delay(clock=4000000) 
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8) 
 
 float func(int x, float y); //prototipo 
 
 main(void) 
 { 
 func(2,2.0,4); 
 return 0; 
 } 
 
 float func(int x, float y) 
 { 
 printf("%f",y/(float)x); 
 return y/(float)x; 
 
 }

 

Un ejemplo un poco más práctico del uso de las funciones lo tenéis aquí.

En siguientes artículos se verán mas cosas sobre el tema de las funciones. Como siempre podéis hacer vuestros comentarios al respecto en el foro


Un saludo y hasta la próxima.

Volver al índice

© 2007-2017 AquiHayapuntes.com