Está en la página 1de 42

 

MANUAL DE MANEJO
DE MIKROC

ZURY JEHEILI SANTIAGO MANZANO.

01/12/2011
 

INDICE

CARACTERÍSTICAS PRINCIPALES DEL MIKROC---------------------------------------3

TIPOS DE DATOS EN MIKROC----------------------------------------------------------------8

VARIABLES Y CONSTANTES-----------------------------------------------------------------10

OPERADORES-------------------------------------------------------------------------------------17

ESTRUCTURAS DE CONTROL---------------------------------------------------------------24

TIPOS DE DATOS AVANZADOS--------------------------------------------------------------30

FUNCIONES-----------------------------------------------------------------------------------------36

2
 

CARACTERÍSTICAS PRINCIPALES DEL MIKROC

  A continuación vamos a presentar a los elementos principales del lenguaje mikroC desarrollado por 

Mikroelektronika. Este lenguaje es muy similar al C estándar, no obstante en determinados aspectos difiere

del ANSI estándar en algunas características. Algunas de estas diferencias se refieren a las mejoras,

destinadas a facilitar la programación de los microcontroladores PIC, mientras que las demás son la

consecuencia de la limitación de la arquitectura del hardware de los PIC. Aquí vamos a presentar 

características específicas del lenguaje mikroC en la programación de los microcontroladores PIC. El término

C se utilizará para referirse a las características comunes de los lenguajes C y mikroC.


Este libro describe una aplicación muy concreta del lenguaje de programación C utilizado en el compilador 

mikroC PRO for PIC. En este caso, el compilador se utiliza para la programación de los microcontroladores

PIC.

3
 

FASES DE COMPILACIÓN

El proceso de compilación consiste en varios pasos y se ejecuta automáticamente por el compilador. Por con,

un conocimiento básico del funcionamiento puede ser útil para entender el concepto del lenguaje mikroC.

El archivo fuente contiene el código en mikroC que usted escribe para programar el microcontrolador. El

preprocesador se utiliza automáticamente por el compilador al iniciarse el proceso de la compilación. El

compilador busca las directivas del preprocesador (que siempre empiezan por µ#¶) dentro del código y modifica

el código fuente de acuerdo con las directivas. En esta fase se llevan a cabo inclusión de archivos, definición

de constantes y macros etc., lo que facilita el proceso. Más tarde vamos a describir estas directivas en detalle.

El analizador sintáctico (parser) elimina toda la información inútil del código (comentarios, espacios en

blanco). Luego, el compilador  traduce el código a un archivo binario denominado archivo .mcl.

El enlazador  (linker) recupera toda la información requerida para ejecutar el programa de los archivos

externos y la agrupa en un solo archivo (.dbg). Además, un proyecto puede contener más de un archivo fuente

y el programador puede utilizar funciones predefinidas y agrupadas dentro de los archivos denominados

librerías. Por último, el generador .hex produce un archivo .hex. Es el archivo que se va a cargar en el

microcontrolador.


El proceso entero de la compilación que incluye todos los pasos anteriormente descritos se le

denomina ³building´ .

4
 

ESTRUCTURA DE PROGRAMA

La idea principal de escribir un programa en C es de ³romper´ un problema mayor en varios trozos más

pequeños. Supongamos que es necesario escribir un programa para el microcontrolador para medir la

temperatura y visualizar los resultados en un LCD. El proceso de medición se realiza por un sensor que

convierte temperatura en voltaje. El microcontrolador utiliza el convertidor A/D para convertir este voltaje (valor 

analógico) en un número (valor digital) que luego se envía al LCD por medio de varios conductores. En

consecuencia, el programa se divide en cuatro partes, de las que cada una corresponde a una acción

específica:

1. Activar y configurar el convertidor A/D incorporado;


2. Medir el valor analógico;
3. Calcular temperatura; y
4. Enviar los datos en el formato apropiado al LCD;

Los lenguajes de programación de alto nivel como es C le permiten solucionar este problema con
facilidad al escribir cuatro funciones que se ejecutarán cíclicamente sin parar.

La idea general es de dividir el problema en varios trozos, de los que cada uno se puede escribir 
como una sola función. Todos los programas escritos en mikroC contienen por lo menos una
función llamada main() que encierra entre llaves {} las sentencias a ser ejecutadas. Esto es la
primera función a ser ejecutada al iniciarse la ejecución de programa. Las otras funciones se
pueden llamar dentro de la función main. En otras palabras, podemos decir que la función main()
es obligatoria, mientras que las demás son opcionales. Si todavía no ha escrito un programa en C,
es probable que todo le resulte confuso. No se preocupe, acéptelo tal como es por el momento y
más tarde entenderá la sintaxis.

5
 

¡Y ahora, su primer programa µreal¶! La figura muestra la estructura de programa, señalando las partes en las

que consiste.


La manera de escribir el código en C es muy importante. Por ejemplo, C difiere entre minúsculas y

mayúsculas, así que la función main() no se puede escribir MAIN() o Main(). Además, note que dos líneas del

código dentro de la función terminan con un punto y coma. En C todas las sentencias deben terminar con un

punto y coma µ;¶, así el compilador puede aislarlas y traducirlas a código máquina.

6
 


 

COMENTARIOS

Los comentarios son las partes del programa utilizados para aclarar las instrucciones de programa o para

proporcionar más información al respecto. El compilador no hace caso a los comentarios y no los compila al

código ejecutable. Dicho de manera sencilla, el compilador es capaz de reconocer los caracteres especiales

utilizados para designar dónde los comentarios comienzan y terminan y no hace nada de caso al texto entre

ellos durante la compilación. Hay dos tipos de tales caracteres. Unos designan los comentarios largos que

ocupan varias líneas de programa marcados por la secuencia especial /*...*/, mientras que otros designan los

comentarios cortos que caben en una sola línea //. Aunque los comentarios no pueden afectar a la ejecución

de programa, son tan importantes como cualquier otra parte de programa. Aquí está el porqué... Con

frecuencia es necesario mejorar, modificar, actualizar, simplificar un programa... No es posible interpretar 

incluso los programas simples sin utilizar los comentarios.

7
 

TIPOS DE DATOS EN MIKROC


En el lenguaje C, los datos tienen un tipo, o sea, cada dato utilizado en el programa debe tener su tipo

especificado. Esto permite al compilador conocer el tamaño de dato (número de bytes requerido en la

memoria) y su representación. Hay varios tipos de datos que se pueden utilizar en el lenguaje de

programación mikroC dependiendo del tamaño de dato y del rango de valores. La tabla muestra el rango de

valores que los datos pueden tener cuando se utilizan en su forma básica.

TAMAÑO
TIPO DE DESCRIPCIÓN (NÚMERO DE RANGO DE VALORES
DATO BITS)

char Texto (caracteres) 8 de 0 a 255

int Valores enteros 16 de -32768 a 32767

de ±1.17549435082·10 -38 a
float Valores en punto flotante 32
±6.80564774407·10 38 

Valores en punto flotante de de ±1.17549435082·10 -38 a


double 32
doble precisión ±6.80564774407·10 38 

*Debido a las limitaciones impuestas por el hardware del microcontrolador, es imposible alcanzar una mayor 

precisión de datos que la del tipo float. Por eso, el tipo double en mikroC equivale al tipo float.

  Al añadir un prefijo (calificador) a cualquier tipo de dato entero o carácter, el rango de sus posibles valores

cambia así como el número de los bytes de memoria necesarios. Por defecto, los datos de tipo int son con

signo, mientras que los de tipo char son sin signo. El calificador signed (con signo) indica que el dato puede

ser positivo o negativo. El prefijo unsigned indica que el dato puede ser sólo positivo. Note que el prefijo es

opcional.

TIPO DE TAMAÑO
TIPO DE DATO (NÚMERO DE RANGO DE VALORES
DATO CON BITS)
PREFIJO

char signed char 8 de -128 a 128

unsigned int 16 de 0 a 65535

short int 8 de 0 a 255

signed
int 8 de -128 a 127
short int

long int 32 de 0 a 4294967295

signed long
32 de -2147483648 a 2147483647
int

8
 

Tipo entero (int)

Un entero es un número sin parte fraccionaria que puede estar expresado en los siguientes formatos:

y Hexadecimal (base 16): el número empieza con 0x (o 0X). Los enteros hexadecimales
consisten en los dígitos (de 0 a 9) y/o las letras (A, B, C,D, E, F). Por ejemplo: µ0x1A¶.
y Decimal (base 10): el número consiste en los dígitos (de 0 a 9). El primer dígito no puede
ser 0. En este formato, se puede introducir el signo de número (µ+¶ o µ-¶). Por ejemplo: 569, -
25, +1500.
y Octal (base 8): los números se representan a base 8 utilizando sólo 8 dígitos (de 0 a 7).
Los enteros octales empiezan con 0. Por ejemplo: µ056¶.
y Binario: cuando un entero empieza con 0b (o 0B) se representan como una serie de bits
(µ0¶ y µ1¶). Por ejemplo: 0B10011111

0x11 // formato hexadecimal equivale a decimal 17 


 
11 // formato decimal 
-152 // formato decimal 
011 // formato octal equivale a decimal 9
0b11 // formato binario equivale a decimal 3 

Tipo punto flotante (float)

El tipo punto flotante (float) se utiliza para los números reales con el punto decimal. Los datos de tipo float se

pueden representar de varias maneras. Un dato float es siempre consigno (signed).

0. // = 0.0 
-1.23 // = -1.23 
23.45e6 // = 23.45 * 10^6  
2e-5 // = 2.0 * 10^-5 
3E+10 // = 3.0 * 10^10 
.09E34 // = 0.09 * 10^34 

Tipo carácter (char)

El tipo char es considerado como un entero por el compilador. No obstante, se utiliza normalmente para los

datos de tipo carácter. Un dato de tipo carácter está encerrado entre comillas y codificado en un carácter 

 ASCII.

59 // entero 
'p' // carácter ASCII 'p' 

Una secuencia de caracteres es denominada cadena (string). Las cadenas están encerradas entre comillas

dobles, por ejemplo:

"Pr esione el botón RA0" 

9
 

VARIABLES Y CONSTANTES

Definiciones

Una variable es un objeto nombrado capaz de contener un dato que puede ser modificado durante la

ejecución de programa. En C, las variables tienen tipo, que significa que es necesario especificar el tipo de

dato que se le asigna a una variable (int, float etc.). Las variables se almacenan en la memoria RAM y el

espacio de memoria que ocupan (en bytes) depende de su tipo.

/* dos líneas de programa consecutivas. En la primera línea del


 programa
se define el tipo de variable */ 
 

int a = 1000; // Variable a es de tipo int y equivale a 1000 


a = 15; // a equivale a 15 

Una constante tiene las mismas características que una variable excepto el hecho de que su valor asignado

no puede ser cambiado durante la ejecución de programa. A diferencia de las variables, las constantes se

almacenan en la memoria Flash del microcontrolador para guardar el mayor espacio posible de memoria

RAM. El compilador las reconoce por el nombre y el prefijo const. En mikroC, el compilador reconoce

automáticamente el tipo de dato de una constante, así que no es necesario especificar el tipo adicionalmente.

/* dos líneas de programa consecutivas */ 


 

const A = 1000 // el valor de la constante A está definido 


A = 15; // ¡ERROR! no se puede modificar el valor de la
constante 

Cada variable o constante debe tener un identificador que lo distingue de otras variables y constantes.

Refiérase a los ejemplos anteriores, a y A son identificadores.

Reglas para nombrar 

En mikroC, los identificadores pueden ser tan largos como quiera. Sin embargo, hay varias restricciones:

y Los identificadores pueden incluir cualquiera de los caracteres alfabéticos A-Z (a-z), los
dígitos 0-9 y el carácter subrayado '_'. El compilador es sensible a la diferencia entre
minúsculas y mayúsculas. Los nombres de funciones y variables se escriben con
frecuencia con minúsculas, mientras que los nombres de constantes se escriben con
mayúsculas.
y Los identificadores no pueden empezar con un dígito.
y Los identificadores no pueden coincidir con las palabras clave del lenguaje mikroC, porque
son las palabras reservadas del compilador.

10
 

El compilador mikroC reconoce 33 palabras clave:

MIKROC - PALABRAS CLAVE

absolute data if return typedef 

asm default inline rx typeid

at delete int sfr typename

auto do io short union

bit double long signed unsigned

bool else mutable sizeof using

break enum namespace static virtual

case explicit operator struct void

catch extern org switch volatile

char false pascal template while

class float private this

code for protected throw

const friend public true

continue goto register try

11
 

Ejemplos de los identificadores válidos e inválidos:

temperatura_V1 // OK 
 
Presión // OK 
 
no_corresponder  // OK 
 
dat2string // OK 
 
SuM3 // OK 
 
_vtexto // OK 
 
7temp // NO -- no puede empezar con un número 
%más_alto // NO -- no pueden contener caracteres
especiales 
if  // NO -- no puede coincidir con una palabra
reservada 
j23.07.04 // NO -- no puede contener caracteres
especiales (punto) 
nombre de variable // NO -- no puede contener espacio en blanco 

Declaración de variables

Cada variable debe ser declarada antes de ser utilizada en el programa. Como las variables se almacenan en

la memoria RAM, es necesario reservar el espacio para ellas (uno, dos o más bytes). Al escribir un programa,

usted sabe qué tipo de datos quiere utilizar y qué tipo de datos espera como resultado de una operación,

mientras que el compilador no lo sabe. No se olvide de que el programa maneja las variables con los nombres

asignados. El compilador las reconoce como números en la memoria RAM sin conocer su tamaño y formato.

Para mejorar la legibilidad de código, las variables se declaran con frecuencia al principio de las funciones:

< tipo> variable;

Es posible declarar más de una variable de una vez si tienen el mismo tipo.

< tipo> variable1, variable2, variable3;

  Aparte del nombre y del tipo, a las variables se les asignan con frecuencia los valores iniciales justamente

enseguida de su declaración. Esto no es un paso obligatorio, sino µuna cuestión de buenas costumbres¶. Se

parece a lo siguiente:

unsigned int peso; // Declarar una variable llamada peso 


peso = 20; // Asignar el valor 20 a la variable peso 

Un método más rápido se le denomina declaración con inicialización (asignación de los valores iniciales):

12
 

unsigned int peso = 20; // peso está declarado y su valor es 20 

Si hay varias variables con el mismo valor inicial asignado, el proceso se puede simplificar:

unsigned int peso1 = peso2 = peso3 = 20;


int valor_inicial = un_mínimo_de_petróleo = 0;

y Tenga cuidado de no declarar la misma variable otra vez dentro de la misma función.
y Puede modificar el contenido de una variable al asignarle un nuevo valor tantas veces que
quiera
y Al declarar una variable, siempre piense en los v alores que la variable tendrá que contener 
durante la ejecución de programa. En el ejemplo anterior, peso1 no se puede representar 
con un número con punto decimal o un número con valor negativo.

Declaración de constantes

Similar a las variables, las constantes deben ser declaradas antes de ser utilizadas en el programa. En

mikroC, no es obligatorio especificar el tipo de constante al declararla. Por otra parte, las constantes deben

ser inicializadas a la vez que se declaran. El compilador reconoce las constantes por su prefijo const utilizado

en la declaración. Dos siguientes declaraciones son equivalentes:

const int MINIMUM = -100; // Declarar constante MINIMUM 


 
const MINIMUM = -100; // Declarar constante MINIMUM 
 

Las constantes pueden ser de cualquier tipo, incluyendo cadenas:

const T_MAX = 3.260E1; // constante de


 punto flotante T_MAX 
 
const I_CLASS = 'A'; // constante
carácter I_CLASS 
const Mensaje = "Presione el botón IZQUIERDA "; // constante de
cadena Mensaje 

Las constantes de enumeración son un tipo especial de constantes enteras que hace un programa más

comprensible al asignar los números ordinales a las constantes. Por defecto, el valor 0 se asigna

automáticamente a la primera constante entre llaves, el valor 1 a la segunda, el valor 2 a la tercera etc.

enum  surtidores {AGUA,GASÓLEO,CLORO}; // AGUA = 0; GASÓLEO = 1;


CLORO = 2 

Es posible introducir directamente el valor de una constante dentro de la lista de enumeraciones. El

incremento se detiene al asignar un valor a un elemento de matriz, después se reinicia a partir del valor 

asignado. Vea el siguiente ejemplo:

13
 

enum  surtidores {AGUA,GASÓLEO=0,CLORO}; // AGUA = 0; GÁSOLEO = 0;


CLORO = 1 

Las constantes de enumeración se utilizan de la siguiente manera:

int Velocidad_de_ascensor 
enum  motor_de_ascensor {PARADA,INICIO,NORMAL,MÁXIMO};
Velocidad_de_ascensor = NORMAL; // Velocidad_de_ascensor = 2 

Definir los nuevos tipos de datos

La palabra clave typedef  le permite crear con facilidad los nuevos tipos de datos.

typedef unsigned int positivo; // positivo es un sinónimo para el


tipo sin signo int 
positivo a,b; // Variables a y b son de tipo
 positivo 
a = 10; // Variable a equivale a 10 
b = 5; // Variable b equivale a 5 

Ámbito de variables y constantes

Una variable o una constante es reconocida por el compilador en base de su identificador. Un identificador 

tiene significado si el compilador lo puede reconocer. El ámbito de una variable o una constante es el rango de

programa en el que su identificador tiene significado. El ámbito es determinado por el lugar en el que se

declara una variable o una constante. Intentar acceder a una variable o una constante fuera de su ámbito

resulta en un error. Una variable o una constante es invisible fuera de su ámbito. Todas las variables y

constantes que pensamos utilizar en un programa deben ser declaradas anteriormente en el código. Las

variables y constantes pueden ser globales o locales. Una variable global se declara en el código fuente, fuera

de todas las funciones, mientras que una variable local se declara dentro del cuerpo de la función o dentro de

un bloque anidado en una función.

14
 


 A las variables globales se les puede acceder de cualquiera parte en el código, aún dentro de las funciones

con tal de que sean declaradas. El ámbito de una variable global está limitado por el fin del archivo fuente en

el que ha sido declarado.

El ámbito de variables locales está limitado por el bloque encerrado entre llaves {} en el que han sido

declaradas. Por ejemplo, si están declaradas en el principio del cuerpo de función (igual que en la

función main) su ámbito está entre el punto de declaración y el fin de esa función. Refiérase al ejemplo

anterior. A las variables locales declaradas en main() no se les puede acceder desde la Función_1 y al revés.

Un bloque compuesto es un gru po de decl ar aciones y sentenci as (que  pueden ser bloques t ambién)

encerr ad as entre ll av es. Un bloque  puede ser una función, una estructur a de control etc. Una  vari able

decl ar ad a dentro de un bloque se consider a loc al, o sea, µexiste¶ sólo dentro del bloque. Sin e mbargo, l as

vari ables decl ar ad as fuer a del ámbito tod avía son v isibles. 

  Aunque las constantes no pueden ser modificadas en el programa, siguen las mismas reglas que las

variables. Esto significa que son visibles dentro de su bloque a excepción de las constantes globales

(declaradas fuera de cualquier función). Las constantes se declaran normalmente en el inicio del código fuera

de cualquier función (como variables globales).

15
 

Clases de almacenamiento

Las clases de almacenamiento se utilizan para definir el ámbito y la vida de variables, constantes y funciones

dentro de un programa. En mikroC se pueden utilizar diferentes clases de almacenamiento:

y  auto es una clase de almacenamiento por defecto para las variables locales, así que se
utiliza raramente. Se utiliza para definir que una variable local tiene duración local. La clase
de almacenamiento auto no se puede utilizar con variables globales.

y  static es una clase de almacenamiento por defecto para las variables globales. Especifica
que una variable es visible dentro del archivo. A las variables locales declaradas con el
prefijo static se les puede acceder dentro del archivo fuente (o sea se comportan como
variables globales).
y  extern: la palabra clave extern se utiliza cuando el programa está compuesto por 
diferentes archivos fuente. Esto le permite utilizar una variable, una constante o una
función declarada en otro archivo. Por supuesto, para compilar y enlazar este archivo
correctamente, el mismo debe ser incluido en su proyecto. En los siguientes ejemplos, el
programa consiste en dos archivos: File_1 y File_2 . El File_1 utiliza una variable y una
función declaradas en File_2 .
File 1: 

extern int cnt; // Variable cnt es visible en File_1 


extern void  hello(); // Función hello()se puede utilizar en
File_1 

void main(){
PORTA = cnt++; // Cualquier modificación de cnt en File_1
será visible en File_2 
hello(); // Función hello()se puede llamar desde aquí 
}

File 2: 

int cnt = 0;
void hello();

void hello(){ // Modificaciones que afectan a la 


. // cnt en File_1 son visibles aquí
.
.
}

16
 

OPERADORES

Un operador es un símbolo que denota una operación aritmética, lógica u otra operación particular. Dicho de

manera sencilla, varias operaciones aritméticas y lógicas se realizan por medio de los operadores. Hay más

de 40 operaciones disponibles en el lenguaje C, pero se utiliza un máximo de 10-15 de ellas en práctica. Cada

operación se realiza sobre uno o más operandos que pueden ser variables o constantes. Además, cada

operación se caracteriza por la prioridad de ejecución y por la asociatividad.

OPERADORES ARITMÉTICOS

Los operadores aritméticos se utilizan en las operaciones aritméticas y siempre devuelven resultados

numéricos. Hay dos tipos de operadores, los unitarios y los binarios. A diferencia de las operaciones unitarias

que se realizan sobre un operando, las operaciones binarias se realizan sobre dos operandos. En otras

palabras, se requieren dos números para ejecutar una operación binaria. Por ejemplo: a+b o a/b.

OPERADOR OPERACIÓN

+ Adición

- Resta

* Multiplicación

  / División

% Resto de la división

int a,b,c; // Declarar 3 enteros a, b, c 


a = 5; // Inicializar a 
b = 4; // Inicializar b 
c = a + b; // c = 9 
c = c%2; // c = 1. Esta operación se utiliza con frecuencia 
// para comprobar la paridad. En este caso, el 
// resultado es 1 lo que significa que la variable 
// es un número imparo 
OPE RADO RE
  S  DE  ASIGN  AC IÓN 

Hay dos tipos de asignación en el lenguaje C:

17
 

y Los operadores simples asignan los valores a las variables utilizando el carácter común '='.
Por ejemplo: a =8
y Las asignaciones compuestas son específicas para el lenguaje C. Consisten en dos
caracteres como se muestra en la tabla a la derecha. Se utilizan para simplificar la sintaxis
y habilitar la ejecución más rápida.
EJEMPLO
OPERADOR
Expresión Equivalente

+= a += 8 a=a+8

-= a -= 8 a=a-8

*= a *= 8 a=a*8

 /= a /= 8 a=a/8

%= a %= 8 a=a%8

int a = 5; // Declarar e inicializar la variable a 


a += 10; // a = a + 10 = 15 

OPE RADO RE
  S  DE  IN CR EMENTO  Y DE CR EMENTO  

Las operaciones de incremento y decremento por 1 se denotan con "++" y "--". Estos caracteres pueden

preceder o seguir a una variable. En primer caso (++x), la variable x será incrementada por 1 antes de ser 

utilizada en la expresión. De lo contrario, la variable se utilizará en la expresión antes de ser aumentada por 1.

Lo mismo se aplica a la operación de decremento

OPERADOR EJEMPLO DESCRIPCIÓN

++  ++a
Variable "a" es

18
 

incrementada por
a++ 
1

--b Variable "a" es


-- decrementada por
b-- 1

int a, b, c;
a = b = 5;
c = 1 + a++; // c = 6 
 
b = ++c + a // b = 7 + 6 = 13 
OPE RADO RE
  S  R EL AC ION 
 ALES  

Los operadores relacionales se utilizan en comparaciones con el propósito de comparar dos valores. En

mikroC, si una expresión es evaluada como falsa (false), el operador devuelve 0, mientras que si una oración

es evaluada como verdadera (true), devuelve 1. Esto se utiliza en expresiones tales como µsi la expresión es

evaluada como verdadera, entonces...¶

OPERADOR DESCRIPCIÓN EJEMPLO CONDICIÓN DE VERACIDAD

> mayor que b>a si b es mayor que a 

>= mayor o igual que a >= 5 si a es mayor o igual que 5 

< menor que a<b si a es menor que b 

<= menor o igual que a <= b si a es menor o igual que b 

== igual que a == 6 si a es igual que 6 

!= desigual que a != b si a es desigual que b 

int prop;
int var = 5;
prop = var  < 10; // Expresión es evaluada como verdadera, prop = 

19
 

OPE RADO RE
  S  LÓGI CO
  S  

Hay tres tipos de operaciones lógicas en el lenguaje C: Y (AND) lógico, O (OR) lógico y negación - NO (NOT)

lógico. Los operadores lógicos devuelven verdadero (1 lógico) si la expresión evaluada es distinta de cero. En

caso contrario, devuelve falso (0 lógico) si la expresión evaluada equivale a cero. Esto es muy importante

porque las operaciones lógicas se realizan generalmente sobre las expresiones, y no sobre las variables

(números) particulares en el programa. Por lo tanto, las operaciones lógicas se refieren a la veracidad de toda

la expresión.

Por ejemplo: 1 && 0 es igual a (expresión verdadera) && (expresión falsa) 

El resultado 0, o sea - Falso en ambos casos.

OPERADOR FUNCIÓN

&&  Y

|| O

! NO

OPE RADO RE
  S  DE  M 
 ANEJO  DE  BITS  

 A diferencia de las operaciones lógicas que se realizan sobre los valores o expresiones, las operaciones de

manejo de bits se realizan sobre los bits de un operando. Se enumeran en la siguiente tabla:

OPERADOR DESCRIPCIÓN EJEMPLO RESULTADO

~   Complemento a uno a = ~b b=5 a = -5

a = 
<<   Desplazamiento a la izquierda a = b << 2 b = 11110011
11001100

a = 
>>  Desplazamiento a la derecha a = b >> 2 b = 11110011
00011110

a = 
c = 
&  Y lógico para manejo de bits c = a &  b 11100011
11000000
b = 11001100

|  O lógico para manejo de bits c=a|b a = 


c = 
11100011

20
 

b = 11001100 11101111

a = 
EXOR lógico para manejo de c = 
^   c=a^b 11100011
bits 00101111
b = 11001100

N ote que el result ado de l a o per ación de des pl azam iento a l a derecha de pende del signo de l a  vari able. En

c aso de que el o per ando se aplique a una vari able sin signo o  positi va, se introducirán los ceros en el es pacio

vac í o creado  por des pl azam iento. Si se aplic a  a un entero con signo neg ati v o, se introducirá un 1  par a 

mantener el signo correcto de l a vari able. 

¿C ÓMO  U TILIZ 
 AR LOS  OPE RADO RE
  S?  

y Aparte de los operadores de asignación, dos operadores no deben estar escritos uno junto
al otro.

x*%12; // esta expresión generará un error 


 

y Cada operador tiene su prioridad y asociatividad como se muestra en la tabla:


y Similar a las expresiones aritméticas, los operadores se agrupan juntos por medio de
paréntesis. Primero se calculan las expresiones encerradas entre paréntesis. Si es
necesario, se pueden utilizar los paréntesis múltiples (anidados).
PRIORIDAD OPERADORES ASOCIATIVIDAD

Alta () [] -> .  de izquierda a derecha

! ~ ++ -- +(unitario) -(unitario) *Puntero &Puntero  de derecha a izquierda

* / %  de izquierda a derecha

+ -  de izquierda a derecha

Baja
< >  de izquierda a derecha

<  <= > >=  de izquierda a derecha

== !=  de izquierda a derecha

& de izquierda a derecha

21
 

^   de izquierda a derecha

|  de izquierda a derecha

&&  de izquierda a derecha

||  de derecha a izquierda

?:  de derecha a izquierda

= += -= *= /= /= &= ^ = |= <= >=  de izquierda a derecha

int a, b, res;
a = 10;
b = 100;
res = a*(a + b); // resultado = 1100 
res = a*a + b; // resultado = 200 

CONVERSIÓN DE TIPOS DE DATOS

 Algunas operaciones implican conversión de datos. Por ejemplo, si divide dos valores enteros, hay una alta

posibilidad de que el resultado no sea un entero. El mikroC realiza una conversión automática cuando se

requiera.

Si dos operandos de tipo diferente se utilizan en una operación aritmética, el tipo de operando de la prioridad

más baja se convierte automáticamente en el tipo de operando de la prioridad más alta. Los tipos de datos

principales se colocan según el siguiente orden jerárquico:


La autoconversión se realiza asimismo en las operaciones de asignación. El resultado de la expresión de la

derecha del operador de la asignación siempre se convierte en el tipo de la variable de la izquierda del

operador. Si el resultado es de tipo de la prioridad más alta, se descarta o se redondea para coincidir con el

tipo de la variable. Al convertir un dato real en un entero, siempre se descartan los números que siguen al

punto decimal.

22
 

int x; // A la variable x se le asigna el tipo integer (un


entero) 
x = 3; // A la variable x se le asigna el valor 3 
x+ = 3.14; // El valor 3.14 se agrega a la variable x al 
// realizar la operación de asignación 

/* El resultado de la adición es 6 en vez de 6.14, como era de


esperar.
Para obtener el resultado esperado sin descartar los números que
siguen al
 punto decimal, se debe declarar x como un punto flotante. */ 
 

Para realizar una conversión explícita, antes de escribir una expresión o una variable hay que especificar el

tipo de resultado de operación entre paréntesis.

ouble distancia, tiempo, velocidad;



distancia = 0.89;
tiempo = 0.1;
velocidad = (int)(a/b); // c = (int)8.9 = 8.0 
velocidad = ((int)a)/b; // c = 0/0.1 = 0.0 

23
 

ESTRUCTURAS DE CONTROL
ESTRUCTURAS CONDICIONALES

Las condiciones son ingredientes comunes de un programa. Las condiciones permiten ejecutar una o varias

sentencias dependiendo de validez de una expresión. En otras palabras, µSi se cumple l a condición (...), se

debe hacer (...). De lo contr ario, si l a condición no se cumple, se debe hacer (...)¶ . Los operandos

condicionales if-else y switch se utilizan en las operaciones condicionales. Una sentencia condicional puede

ser seguida por una sola sentencia o por un bloque de sentencias a ser ejecutadas.
OPE RADO R C ON DI CI ON   AL if-else

El operador if se puede utilizar solo o asociado al operador  else (if-else) .

Ejemplo del operador  if :

if(expresión) operación;

Si el resultado de la expresión encerrada entre paréntesis es verdadero (distinto de 0) la operación se realiza

y el programa continúa con la ejecución. Si el resultado de la ex  presión es falso (0), la o per ación no se realiza

y el programa continúa inmediatamente con la ejecución.

Como hemos mencionado, la otra forma combina tanto el operador if como el else:

if(expresión) operación1 else operación2;

Si el resultado de la ex  presión es verdadero (distinto de 0), se realiza o per ación1, de lo contrario se realiza

la o per ación2 . Después de realizar una de las operaciones, el programa continúa con la ejecución.

La sentencia if-else se parece a lo siguiente:

if(expresión)
operación1
else 
operación2

Si operación1 u operación2 está compuesta, escriba una lista de sentencias encerradas entre llaves. Por 

ejemplo:

if(expresión) {
 
... // 
... // operación1 
...} //  
else 
operación2

El operador if-else se puede sustituir por el operador condicional '?:':

24
 

(expresión1)? expresión2 : expresión3

Si el valor de la ex 
 presión1 es distinto de 0 (verdadero), el resultado de la expresión entera será equivalente al

resultado obtenido de laex  presión2 . De lo contrario, si la ex 


 presión1 es 0 (falso), el resultado de la expresión

entera será equivalente al resultado obtenido de laex 


 presión3. Por ejemplo:

maximum = (a>b)? a : b // A la variable maximum se le asigna el 


// valor de la variable mayor(a o b) 

 perador  Sw itch

  A diferencia de la if-else que


sentencia selecciona entre dos opciones en el programa, el

operador switch permite elegir entre varias opciones. La sintaxis de la sentencia switch es:

switch (selector) // Selector es de tipo char o int 


{
case constante1:
operación1 // El grupo de operadores que se ejecutan si 
... // el selector y la constante1 son
equivalentes 

 break ;

case constante2:

operación2 // El grupo de operadores se ejecuta si 


... // el selector y la constante2 son
equivalentes 

 break ;
...
default:

operación_esperada // El grupo de operadores que se


ejecuta si 
... // ninguna constante equivale al
selector 
 
 break;
}

La operación switch se ejecuta de la siguiente manera: primero se ejecuta el selector y se compara con la

constante1. Si coinciden, las sentencias que pertenecen a ese bloque se ejecutan hasta llegar a la palabra

clave break o hasta el final de la operación switch. Si no coinciden, el selector se compara con la constante2.

Si coinciden, las sentencias que pertenecen a ese bloque se ejecutan hasta llegar a la palabra clave break

etc. Si el selector no coincide con ninguna constante, se ejecutarán las operaciones que siguen al operador 

default.

25
 

También es posible comparar una expresión con un grupo de constantes. Si coincide con alguna de ellas, se

ejecutarán las operaciones apropiadas:

switch (días) // La variable días representa un día de la semana. 


{ // Es necesario determinar si es un día laborable o no lo es 
case1:case2:case3:case4:case5: LCD_message = 'Día laborable';
 break;
case6:case7: LCD_message = 'Fin de semana';  break;
default:LCD_message_1 = 'Elija un día de la semana';  break;
}

La  pal abr a cl av e de C µbreak ¶ se  puede utili zar en cualquier ti  po de bloques. Al utili zar µbreak ¶, es  posible salir 

de un bloque aunque l a condición  par a su final no se hay a cumplido. Se  puede utili zar  par a ter minar un bucle

infinito, o  par a for zar un bucle a ter minar antes de lo nor mal. 


BUCLES

  A menudo es necesario repetir una cierta operación un par de veces en el programa. Un conjunto de

comandos que se repiten es denominado un bucle de programa. Cuántas veces se ejecutará, es decir cuánto

tiempo el programa se quedará en el bucle, depende de las condiciones de salir del bucle.

Bucle While

El bucle w hile se parece a lo siguiente:

 while(expresión){
comandos
...
}

Los comandos se ejecutan repetidamente (el programa se queda en el bucle) hasta que la expresión llegue a

ser falsa. Si la expresión es falsa en la entrada del bucle, entonces el bucle no se ejecutará y el programa

continuará desde el fin del bucle while.

Un tipo especial del bucle de programa es un bucle infinito. Se forma si la condición sigue sin cambios dentro

del bucle. La ejecución es simple en este caso ya que el resultado entre llaves es siempre verdadero

(1=verdadero), lo que significa que el programa se queda en el mismo bucle:

 while(1){ // En vez de "while(1)", se puede escribir 


"while(true)" 
... // Expresiones encerradas entre llaves se ejecutarán 
... // repetidamente (bucle infinito) 
}

Bucle For 

26
 

El bucle for se parece a lo siguiente:

for(expresión_inicial; expresión_de_condición; cambiar_expresión)


{
operaciones
...
}

La ejecución de esta secuencia de programa es similar al bucle w hile, salvo que en este caso el proceso de

especificar el valor inicial (inicialización) se realice en la declaración. La expresión_ inicial especifica la

variable inicial del bucle, que más tarde se compara con la expresión_ de_condición antes de entrar al bucle.

Las operaciones dentro del bucle se ejecutan repetidamente y después de cada iteración el valor de la

expresión_inicial se incrementa de acuerdo con la regla cambiar_expresión. La iteración continúa hasta que la

expresión_de_condición llegue a ser falsa.

for(k=0; k<5; k++) // La variable k se incrementa 5 veces (de 1 a


4) y 
 
operación // cada vez se repite la expresión operación 
...

La operación se ejecutará cinco veces. Luego, al comprobar se valida que la expresión k<5 sea falsa

(después de 5 iteraciones k=5) y el programa saldrá del bucle for.

Bucle Do-while

El bucle do-w hile se parece a lo siguiente:



operación
 while (cambiar_condición);

La expresión cambiar_condición se ejecuta al final del bucle, que significa que operación se ejecuta como

mínimo una vez sin reparar en que si la condición es verdadera o falsa. Si el resultado es distinto de 0

(verdadero), el procedimiento se repite.

Todos los siguientes ejemplos son equivalentes. Esta parte del código visualiza "hello" en un LCD 10 veces

con un retardo de un segundo. Note que en este ejemplo se utilizan funciones predefinidas, que se

encuentran en las librerías del compilador  mi k roC PRO for PIC . No obstante le aconsejamos que no trate de

entenderlas en detalle. Su comportamiento general dentro del bucle se explica por medio de los comentarios.

i = 0; // Inicialización del contador 


 

 while (i<10) { // Condición 


Lcd_Out(1,3,"hello"); // Visualizar ³hello´ en el LCD 
 
Delay_ms(1000); // Retardo de 1000 ms 

27
 

Lcd_Cmd(_LCD_CLEAR); // Borrar el LCD 


 
Delay_ms(500); // Retardo de 500ms 
i++; // Contador se incrementa 
}
for(i=0; i<10; i++) { // Inicialización, condición,
incremento 
Lcd_Out(1,3,"hello"); // Visualizar ³hello´ en el LCD  
Delay_ms(1000); // Retardo de 1000 ms 
Lcd_Cmd(_LCD_CLEAR); // Borrar el LCD 
 
Delay_ms(500); // Retardo de 500ms 
}
i = 0; // Inicialización del contador 
 
d  {
o
Lcd_Out(1,3,"hello"); // Visualizar ³hello´ en el LCD   
Delay_ms(1000); // Retardo de 1000 ms 
Lcd_Cmd(_LCD_CLEAR); // Borrar LCD 
 
Delay_ms(500); // Retardo de 500ms 
i++; // Contador se incrementa 
}
 while (i<10); // Condición 

SENTENCIAS DE SALTO
SENTEN C A
 I  BR E AK 
 

 A veces es necesario detener y salir de un bucle dentro de su cuerpo. La sentencia break se puede utilizar 

dentro de cualquier bucle (while, for, do while) y en las sentencias switch también. En éstas la sentencia break

se utiliza para salir de las sentencias switch si la condición case es verdadera. En este ejemplo, ³Esperar´ está

parpadeando en la pantalla LCD hasta que el programa detecte un uno lógico en el pin 0 del puerto PORTA.

 while(1){ // Bucle infinito 


if(PORTA.F0 == 1) // Probar si el estado lógico del pin 0
del puerto 
break; // PORTA es 1; si equivale, salir del
bucle 
Lcd_Out(1,3,"Esperar"); // Visualizar ³Esperar´ en el LCD 
 
Delay_ms(1000); // Retardo de 1000 ms 
Lcd_Cmd(_LCD_CLEAR); // Borrar LCD 
 
Delay_ms(500); // Retardo de 500ms 
}
SENTEN C A
 I  C ONTIN UE
    

La sentencia continue colocada dentro de un bucle se utiliza para saltar una iteración. A diferencia de la

sentencia break, el programa se queda dentro del bucle y las iteraciones continúan.

// Si x=7, puede ocurrir una división por 0.


// continue se utiliza aquí para evitar esta situación. 
28
 

x=1;
 while (x<=10) {
if (x == 7) { // saltar x=7 para evitar división por 0 
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,3,"Division by 0");
Delay_ms(1000);
x++;
continue; // Después de esta línea, saltar a la sentencia
while con x=8 
}

a = 1/(x-7); // Esta división generará un error si x=7 

 
/* Muchas operaciones pueden ocurrir aquí */ 

Lcd_Out(1,3,"Division is OK"); // Poner este mensaje en el LCD 


 
Delay_ms(1000);
x++;
}
SENTEN C A
 I  GOTO  

La sentencia goto le permite hacer un salto absoluto al otro punto en el programa. Esta característica se debe

utilizar con precaución ya que su ejecución puede causar un salto incondicional sin hacer caso a todos los

tipos de limitaciones de anidación. El punto destino es identificado por una etiqueta, utilizada como un

argumento para la sentencia goto. Una etiqueta consiste en un identificador válido seguido por un colon (:).

...

if(CO2_senso r) goto aire acondicionado; // Si se consta que el


valor 
 
... // de la variable
CO2_sensor =1 
// hacer salto a la línea
de programa 
// Aire acondicionado 
...
Aire acondicionado: // Desde aquí sigue la
 parte del código que se ejecutará 
// en caso de una
concentración de CO2 demasiado alta 
... // en el ambiente 

29
 

TIPOS DE DATOS AVANZADOS


MATRICES

Una matriz es una lista de elementos del mismo tipo colocados en localidades de memoria contiguas. Cada

elemento es referenciado por un índice. Para declarar una matriz, es necesario especificar el tipo de sus

elementos (denominado tipo de matriz), su nombre y el número de sus elementos encerrados entre corchetes.

Todos los elementos de una matriz tienen el mismo tipo.

tipo_ de _  m atriz nombre_de_matriz [nº_de_elementos];

Los elementos de una matriz se identifican por su posición. En C, el índice va desde 0 (el primer elemento de

una matriz) a N-1 (N es el número de elementos contenidos en una matriz). El compilador tiene que ³saber´

cuántas localidades de memoria debe alojar al declarar una matriz. El tamaño de una matiz no puede ser una

variable. Por eso, se pueden utilizar dos métodos:

// método 1 
int display [3]; // Declaración de la matriz display capaz de
contener 3 enteros
// método 2 
const DÍGITOS = 5;
char Matriz_nueva[DÍGITOS]; // Declaración de la matriz
Matriz_nueva 
// capaz de contener 5 enteros 

Una matriz se puede inicializar a la vez que se declara, o más tarde en el programa. En ambos casos, este

paso se realiza al utilizar llaves:




int array_1[3] = {10,1,100};

30
 

Para leer o modificar un elemento de matriz del ejemplo anterior, basta con introducir su índice encerrado

entre corchetes:

/* Se supone que a ha sido declarado anteriormente como un entero


*/ 
 

a = array_1[0]; // A la variable a se le asigna el valor del


miembro de matriz 

// con índice 0 (a = 10) 


array_1[2] = 20; // Miembro de matriz array_1[2] es modificado
(nuevo valor es 20) 

El siguiente programa cambia el orden de los elementos de una matriz. Note que el índice se puede expresar 

mediante variables y operaciones básicas.

void main() {
const MUESTRAS_DE_AGUA = 4; // Valor de la constante
MUESTRAS_DE_AGUA es 4 
int i, temp; // Variables i y temp son de tipo int 
int profunidad_de_sonda [MUESTRAS_DE_AGUA] = {24,25,1,1987};// 
Todos 

// los miembros de la matriz profundidad 


 
// de sonda son de tipo int 

for(i=0;i<(MUESTRAS_DE_AGUA/2);i++){ // Bucle se ejecuta 2


veces 
temp = profundiad_de_sonda [i]; // temp se utiliza para
guardar un valor 
 
// temporalmente 
profundiad_de_sonda [i] = p rofundiad_de_sonda
[MUESTRAS_DE_AGUA-1-i];
profundiad_de_sonda [MUESTRAS_DE_AGUA-1-i] = temp;
}

// Aquí tenemos: profundidad_de_sonda [MUESTRAS_DE_AGUA] = 


{1987,1,25,24} 
}

MATRICES BIDIMENSIONALES

 Aparte de las matrices unidimensionales que se pueden interpretar como una lista de valores, el lenguaje C le

permite declarar matrices multidimensionales. En esta parte vamos a describir sólo las matrices

bidimensionales, también denominadas tablas o matrices. Una matriz bidimensional se declara al especificar 

el tipo de dato de matriz, el nombre de matriz y el tamaño de cada dimensión.

31
 

tipo_ de _  m atriz nombre_de_matriz [número_de_filas]


[número_de_columnas];

En la declaración de esta matriz número_de_filas y número_de_columnas representan el número de filas y

columnas en las que consiste una tabla, respectivamente. Vea la siguiente matriz bidimensional:

int Tabla [3][4]; // Tabla se define de modo que tenga 3 filas y 


4 columnas 

Esta matriz se puede representar en la forma de una tabla.

tabla[0][0] tabla[0][1] tabla[0][2] tabla[0][3]

tabla[1][0] tabla[1][1] tabla[1][2] tabla[1][3]

tabla[2][0] tabla[2][1] tabla[2][2] tabla[2][3]

Similar a las matrices unidimesionales, es posible asignar los valores a los elementos de una tabla en la línea

de declaración. La asignación debe ser realizada línea a línea como en el siguiente ejemplo. Como hemos

visto anteriormente, esta matriz tiene dos filas y tres columnas:

int Tabla [2][3]= { {3,42,1},{7,7,19} };

La matriz anterior se puede representar también en la forma de una tabla de valores:

3 42 1

7 7 19

PUNTEROS

Un puntero es una variable destinada a recibir una dirección. Un puntero ³apunta´ a una localidad de memoria,

referenciada por una dirección. En C, la dirección de un objeto se puede obtener por medio un operador 

unitario &. Para acceder al contenido de la memoria en una dirección específica (también llamado objeto

apuntado), se utiliza un operador de indirección (*).

32
 


'&n' es la dirección de la localidad de memoria 'n'.

'*(&n)' es el contenido de la dirección '(&n)', o sea de 'n'.

Para declarar un puntero, se debe que especificar el tipo de la variable apuntada:

tipo_ de _ varia ble *puntero;

En esta etapa, el puntero mi_puntero apunta al valor almacenado en esta localidad de memoria, o sea, a un

valor desconocido. Así que, una inicialización es muy recomendable:

puntero = &variable;

 Ahora,  puntero contiene la dirección de vari able.

Para acceder al contenido de la variable apuntada, debe utilizar µ*¶. El siguiente ejemplo muestra el contenido

de memoria dependiendo de la acción realizada por medio del puntero.


Los punteros son muy útiles para manejar las matrices. En este caso, un puntero se utilizará para apuntar al

primer elemento de una matriz. Debido al hecho de que es posible realizar operaciones básicas sobre los

punteros (aritmética de punteros), es fácil manejar los elementos de una matriz.

Fíjese en la diferencia entre µ*v+1¶ y µ*(v+1)¶ en el siguiente ejemplo:

short int voltio[3] = {0,5,10};

33
 

short int *v;


v = &(voltio[0]); // v contiene la dirección de voltio[0] 
*(v+1) = 2; // voltio[1] = 2 
voltio[2] = *v+1; // tab[2] = 1 (tab[0] + 1) 
*(v+2) = *(v+1); // voltio[2] = 2 
v++; // v contiene la dirección de voltio[1] 
*v = 1; // voltio[1] = 1 

 
y Los  punterost ambién  pueden ser decl ar ados con el  prefijo µconst¶. En este c aso, su valor 
no  puede ser modific ado des pués de l a inici ali zación, si mil ar a una const ante. 
   A diferenci a de C, el mi kr  oC no ad mite aloj amiento dinámico. 
y

ESTRUCTURAS

Ya hemos visto cómo agrupar los elementos dentro de matrices. No obstante, al utilizar este método todos los

elementos deben ser del mismo tipo. Al utilizar estructuras, es posible agrupar diferentes tipos de variables

bajo el mismo nombre. Las variables dentro de una estructura se le denominan los miembros de la estructura.

Las estructuras de datos se declaran al utilizar la siguiente sintaxis:

struct nombre_de_estructura {
tipo1 _ de _  m ie mbro1 miembro1;
tipo2_ de _  m ie mbro2 miembro2;
tipo3_ de _  m ie mbro3 miembro3;
..
};

No es posible inicializar variables dentro de la declaración de la estructura de datos:

struct generador {
int voltaje;
char corriente;
};

Entonces, podrá definir los objetos denominados µturbina¶ en el código. A cada uno de estos tres objetos

(turbinas) se le asignan las variables µcorriente¶ y µvoltaje¶.

struct generadores turbina_1, turbina_2, turbina_3;

Para acceder a las variables, es preciso utilizar el operador '.'

turbina_3.voltaje = 150;

turbina_3.corriente = 12;

34
 

Por supuesto, igual que al utilizar los punteros, todavía se le permite realizar operaciones por medio de

operadores y sentencias definidos en las partes anteriores.

Si está f amili ari zado con el lengua je C, recuerde que mi kr  oC no ad mite l a inici ali zación de los miembros de

estructur a  por medio de l as ll av es. Por ejemplo, µconjunto_1 ={15,µ m¶};¶ dev uel ve


  un error en mi k roC. 

FUNCIONES
Una función es una subrutina que contiene una lista de sentencias a realizar. La idea principal es dividir un

programa en varias partes utilizando estas funciones para resolver el problema inicial con más facilidad.

  Además, las funciones nos permiten utilizar las destrezas y el conocimiento de otros programadores. Una

función se ejecuta cada vez que se llame dentro de otra función. En C, un programa contiene como mínimo

una función, la función main(), aunque el número de funciones es normalmente mayor. Al utilizar funciones el

código se hace más corto ya que es posible llamar una función tantas veces como se necesite. En C, el

35
 

código normalmente consiste en muchas funciones. No obstante, en caso de que su programa sea muy corto

y simple, puede escribir todas las sentencias dentro de la función principal.

FUNCIÓN PRINCIPAL

La función principal main() es una función particular puesto que es la que se ejecuta al iniciar el programa.

  Además, el programa termina una vez completada la ejecución de esta función. El compilador reconoce

automáticamente esta función y no es posible llamarla por otra función. La sintaxis de esta función es la

siguiente:

void main (void 
) {

/* el primer 'void' significa que main no devuelve ningún valor.


El segundo
'void' significa que no recibe ningún valor. Note que el
compilador 
también admite la siguiente sintaxis: 'main()' o 'void main()' o
'main(void)' */ 
 

..

 
/* --- Introduzca su programa aquí --- */ 

.
};

Esto significa que f es una función que recibe un número real x como parámetro y devuelve 2*x-y.

La misma función en C se parece a lo siguiente:

float f (float x, float y) // variables flotantes x y y se pueden


utilizar en f 
 
{
float r; // declarar r para almacenar el resultado 
r = 2*x - y; // almacenar el resultado del cálculo en r  
return r; // devolver el valor de r 
 
}

Cada función debe ser declarada apropiadamente para poder interpretarla correctamente durante el proceso

de compilación. La declaración contiene los siguientes elementos:

y Tipo de resultado (valor devuelto): tipo de dato del valor devuelto


y Nombre de función: es un identificador que hace posible llamar a una f unción.
y Declaración de parámetros se parece a la declaración de variable regular (por ejemplo:
float x). Cada parámetro consiste en una variable, constante, puntero o matriz, precedidos

36
 

por la etiqueta de tipo de dato. Se utilizan para pasar la información a la función al llamarla.
Los parámetros diferentes están delimitados por comas.
y Cuerpo de función: bloque de sentencias dentro de llaves
Una función se parece a lo siguiente:

tipo_ de _ resultad 
o nombre_de_función (tipo argumento1, tipo 
argumento2,...)
{
Sentencia;
Sentencia;
...
return ...
}

N ote que una función no necesit a  parámetros (función main()  por ejemplo),  pero debe est ar entre  paréntesis.

En c aso contr ario, el compil ador malinter  pret ar ía l a función. P ar a hacerlo más cl aro,  puede sustituir el es pacio

en bl anco encerr ado entre  paréntesis  por l a  pal abr a cl av e v oid: main ( vo
  id). 
VALOR DEVUELTO

Una función puede devolver un valor (esto no es obligatorio) por medio de la palabra clave return. Al llegar a

return, la función evalúa un valor (puede ser una expresión) y lo devuelve a la línea de programa desde la que

fue llamada.

return r; // Devolver el valor contenido en r 


 
return (2*x - y); // Devolver el valor de la expresión 2*x-y 
 

Una función no puede devolver más de un valor, pero puede devolver un puntero o una estructura. Tenga

cuidado al utilizar matrices y punteros. El siguiente ejemplo es un error típico:

int *reverse(int *tab) // Esta función debe devolver una matriz r 


 
{ // cuyo contenido está en orden inverso
con 
// respecto a la matriz tab 
int r[DIM]; // Declaración de una nueva matriz denominada r 
 
int i;
for(i=0;i<DIM;i++) // Bucle que copia el contenido de tab
en r 
 
r[i] = tab[DIM-1-i]; // al invertir el orden 

return r; // Devolver el valor r 


 
}

En realidad, el compilador reserva memoria para el almacenamiento de variables de la función reverse sólo

durante su ejecución. Una vez completada la ejecución de reverse, la localidad de memoria para la variable i o

37
 

para la matriz r ya no está reservada. Esto significa que la dirección que contiene los valores de i o r[] está

libre para introducir datos nuevos. Concretamente, la función devuelve sólo el valor &r[0], así que sólo el

primer elemento de la matriz tab será almacenado en la memoria. Las demás localidades de memoria, tales

como &tab[1], &tab[2], etc. serán consideradas por el compilador como espacios en blanco, o sea, estarán

listas para recibir los nuevos valores.

Para escribir esta función es necesario pasar la matriz r [] como parámetro (vea la subsección Pasar los

parámetros).

La función puede contener más de una sentencia return. En este caso, al ejecutar la primera sentencia return,

la función devuelve el valor correspondiente y se detiene la ejecución de la función.

float abs (float x, float y) // Devolver el valor absoluto de


2*x-y 
 
{
if ((2*x - y) >= 0)
return (2*x - y);
else 
return (-2*x + y);
}

Si la función no devuelve ningún valor, la palabra void debe ser utilizada como un tipo de resultado en la

declaración. En este caso, la sentencia return no debe ser seguida por ninguna expresión. Puede ser omitida

como en el siguiente ejemplo:

void wait_1 (unsigned int a)


{
cnt ++; // Incremento de una variable global cnt 
Delay_ms(a) ; // Ejecución de la función Delay_ms 
} // Note que Delay_ms no devuelve nada 

DECLARAR PROTOTIPOS DE FUNCIONES

Para utilizar una función, el compilador debe ser consciente de su presencia en el programa. En la

programación en C, los programadores normalmente primero escriben la función main() y luego las funciones

adicionales. Para avisar al compilador de la presencia de las funciones adicionales, se requiere declarar los

prototipos de funciones en el principio de programa antes de la función main(). Un prototipo de función está

compuesto por:
y tipo de resultado
y nombre de función
y tipos de parámetros
y un punto y coma (;)

38
 

El prototipo de la función main no necesita ser declarado.

float f (float, float);

/* no es obligatorio escribir los nombres de los parámetros. Este


 prototipo
informa al compilador: en el programa se utilizará la función f,
que utiliza dos parámetros de tipo float y devuelve el resultado
del tipo
float. */ 
 

LLAMAR UNA FUNCIÓN

Mientras una función es definida y su prototipo declarado, se puede utilizar en culquier parte de programa. Sin

embargo, como la funciónmain es 'raiz' del programa, no puede ser llamada de ninguna parte de programa.

Para ejecutar una función, es necesario escribir su nombre y los parámetros asociados. Vea los siguientes

ejemplos:

float  resultado,a,b; // resultado,a,b,time deben coincidir con


los tipos 
// definidos 
int time = 100; // en la declaración de las funciones f y 
wait_1 
a = 10.54;
b = 5.2;
resultado = f(a,b); // Ejecutar la función f por medio de los
 parámetros a y b 

// El valor devuelto se le asigna a la


variable resultado 
pausa_1(tiempo); // Ejecutar la función pausa_1 por medio de
la variable tiempo 
funciónX(); // Ejecutar la función funciónX (sin
 parámetros) 

Cuando se llama una función, el programa salta a la función llamada, la ejecuta, después vuelve a la línea

desde la que fue llamada.

PASAR LOS PARÁMETROS

 Al llamar una función, se le pasan los parámetros. En C existen dos formas diferentes para pasar parámetros

a una función.

El primer método, denominado µpaso por valor¶, es el más fácil. En este caso, los parámetros se pueden

considerar como variables locales de la función. Cuando se llama una función, el valor de cada parámetro se

copia a un nuevo espacio de memoria reservado durante la ejecución de la función. Como los parámetros se

39
 

consideran como variables locales por el compilador, sus valores pueden ser modificados dentro de la función,

pero sus modificaciones no se quedan en la memoria una vez completada la ejecución de la función.

Tenga en cuenta de que la función devuelve un valor, y no una variable. Además, se crean copias de los

valores de los parámetros, por lo que sus nombres en la función f pueden ser diferentes de los parámetros

utilizados en la main(). La mayor desventaja del µpaso por el valor¶ es que la única interacción que una función

tiene con el resto del programa es el valor devuelto de un solo resultado (o la modificación de las variables

globales).

El otro método, denominado 'paso por dirección' le permite sobrepasar este problema. En vez de enviar el

valor de una variable al llamar a función, se debe enviar la dirección de memoria del valor. Entonces, la

función llamada será capaz de modificar el contenido de esta localidad de memoria.

// Función 'sort'ordena los miembros de la matriz por valor 


ascendente
// y devuelve el miembro con máximo valor 
 

int sort(int *); // Prototipo de función 


const SIZE = 5; // Número de miembros a ordenar 
 

void main() {
int maximum, input[SIZE] = {5,10,3,12,0}; // Declaración de
variables en la matriz 
maximum = sort(input); // Llamar a función
y asignarle el máximo 
// valor a la variable maximum 
}

int sort(int *sequence) {


int i, temp, permut; // Declaración de variables 
permut = 1; // Bandera de bit indica que se ha
hecho una permutación 

 while(permut!=0) { // Quedarse en el bucle hasta reinicar 


la bandera
permut = 0; // Bandera reiniciada 
for(i=0;i<SIZE-1;i++) { // Comparar y oredenar los miembros
de la 
// matriz (dos a dos)
if(sequence [i] > sequence[i+1]){
temp = sequence [i];
sequence[i] = sequence[i+1];
sequence[i+1] = temp;
permut = 1; // Se ha hecho una permutación, bandera de
bit 
//se pone a uno 
}

40
 

}
}

return sequence[SIZE-1]; // Devolver el valor del último


miembro 

} // que es al mismo tiempo el miembro con el máximo valor 


 

En este ejemplo, por medio de una función se realizan dos operaciones: ordena los miembros de la matriz por 

valor asdendente y devuelve el máximo valor.

Para utilizar una matriz en una función es necesario asignar la dirección a la matriz (o a su primer miembro).

Vea el siguiente ejemplo:

float método_1(int[]); // Declaración de prototipo de la


función Método_1 
float método_2(int*); // Declaración de prototipo de la
función Método_2 

const NÚMERO_DE_MEDICIONES = 7; // Número de los miembros de la


matriz 

void main()
{
ouble promedio1, promedio2; // Declaración de las variables

 promedio1 
// y promedio2 
int voltaje [NÚMERO_DE_MEDICIONES] = {7,8,3,5,6,1,9}; // 
Declaración de la 
// matriz
voltaje 
promedio1 = método_1(&voltaje[0]); // Parámetro de la función
es la dirección 
// del primer miembro 
promedio2 = método_2(voltaje); // Parámetro de la función es la
dirección de 
// la matriz 
}

//×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
××××× 
float método_1(int voltaje[]) // Inicio de la función
método_1 
{
int i, suma; // Declaración de las
variables locales i y suma 

41
 

for(i=0;i<NÚMERO_DE_MEDICIONES;i++) // Cálculo del valor 


 promedio de voltaje 
suma += voltaje[i]; // Es posible utilizar 
*(voltaje+i)en vez de voltaje[i] 

return(suma/NÚMERO_DE_MEDICIONES);
}

//×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
××××× 
float método_2 (int *voltaje) //Inicio de la función método_2 
{
int i, suma; // Declaración de las variables
locales i y suma 

for(i=0;i<NÚMERO_DE_MEDICIONES;i++) // Cálculo del valor 


 promedio de voltaje 
suma += *(voltaje+i); // Es posible utilizar 
voltaje[i] en vez de *(voltaje+i) 

return(suma/NÚMERO_DE_MEDICIONES);
}

Las funciones 'método_1' y 'método_2' son completamente equivalentes. Las dos devuelven el valor promedio

de la matriz 'voltaje[]'. Después de declararla, la dirección del primer miembro se puede escribir como 'voltaje'

o '&voltaje[0]'.

42

También podría gustarte