View
4
Download
2
Category
Preview:
Citation preview
Programación en C para sistemas basados en un microprocesador
Una introducción
Objetivos• Recordar los conceptos básicos de un lenguaje de
alto nivel
• Comprender sencillos programas escritos en el lenguaje más empleado: “C”
• Comparar las características de “C” con las de Java y el lenguaje ensamblador.
Lenguajes de alto nivel
• Basados en el uso de compiladores o intérpretes• Incrementan la productividad (respecto al ensamblador)
– Estructuras elegantes de control– Complejas estructuras de datos– Mayor abstracción:
• Manejo de la pila: funciones • Memoria física: variables y tipos
– Incrementan la seguridad• Programación estructurada (sin branches)• Control de tipos (coherencia de tamaños y signos)
• Incrementan la portabilidad (multimáquina)• Se dispone de más bibliotecas que facilitan la
programación
¿Por qué “C”?
• Permite un buen control de los recursos de bajo nivel (aunque no tanto como el ensamblador)
• Permite la programación estructurada• Es eficiente en velocidad y tamaño (aunque no tanto
como un buen programa de un buen programador en ensamblador)
• Su uso está muy extendido en programación de sistemas (Linux, Windows, drivers...)
• Defecto: es fácil cometer errores: – No está fuertemente tipado ni es orientado a objetos– Permite crear código críptico– Es difícil de dominar con maestría
Traducción a ensamblador• 0200fc linkw %fp,#-4• 020100 nop• 020102 clrl %fp@(-4)• 020106 moveq #9,%d0• 020108 cmpl %fp@(-4),%d0• 02010c bges 00020110• 02010e bras 00020138• 020110 moveal %fp@(8),%a0• 020114 addal %fp@(-4),%a0• 020118 moveal %fp@(12),%a1• 02011c addal %fp@(-4),%a1• 020120 moveb %a0@,%d0• 020122 extbl %d0• 020124 moveb %a1@,%d1• 020126 extbl %d1• 020128 cmpl %d0,%d1• 02012a beqs 00020130• 02012c moveq #1,%d0• 02012e bras 0002013e• 020130 moveq #1,%d0• 020132 addl %d0,%fp@(-4)• 020136 bras 00020106
•Parameter s1 is at 8(A7)•Parameter s2 is at 12(A7)•Variable i is at -4(A7)•Return value through -4(A7)
•int stringCmp(char s1[10],char s2[10]) {• int i; • for (i=0; i<10; i++)• { • if (s1[i]!=s2[i])
• {
•
• return 1; • }
• }• return 0;• }
Variables Locales: seguridad, abstrae memoria y pila
Bucle: cómodo y estructurado
Escribir cómodamente expresiones complejas
Manejo transparente de pila y registros
Proceso de compilación
Fichero.c GCC Fichero.s AS Fichero.o
LD
Fichero.hcfFichero.elf
Fichero.dep OBJDUMP
main.oASMain.asg
“C” versus Java• “C” no es un lenguaje orientado a objetos:
– No hay clases, objetos, métodos– No hay herencia, polimorfismo (no puede haber 2
funciones con el mismo nombre)– No hay objetos sino variables– No hay métodos de una clase sino funciones– No hay excepciones
• “C” no es un lenguaje interpretado
• No es “machine-independent”
Puntos comunes con Java (I)
• Bloques definidos por llaves• El ámbito de una variable es el bloque más pequeño
que contiene su declaración (salvo para los argumentos de una función)
• Comentarios: /* ... */• Tipos comunes:
– Los básicos: void, char, int, float– Los modificadores long, short, double, signed y unsigned– Definición de nuevos tipos mediante typedef
• Identificadores: case-sensitive, no deben empezar por un número. – Ej: linea5, linea_5, linea_anterior
Puntos comunes con Java (II)• Expresiones comunes:
– Los paréntesis son los elementos más prioritarios, seguidos por los operadores unitarios y por los binarios
– Operadores aritméticos: + - * / % ++ -- += -= *= /=•I+=5+(5%2); /* I=i+6*/
– Operadores lógicos y relacionales: && || ! < <= > >= == !=•if ((i>0 && i<10) || (j==0) ) { }
– Operadores de bit y de desplazamiento: & | >> <<•I=0xf0 & 0x0f; /* I=0 */•I=j<<3; /* ASL de 3 bits*/
Puntos comunes con Java (III)
• Bucles– for (inicialización; condición; iteración)
•for (i=0; i<10; i++) { }•for (int i=0;...) /* ERROR */
– while (condición)•while (i<10) { i++; }
• Condiciones:– if (<cond>) {} else if (<cond>) {} else { }
•if (i<0) { } else if (i<10) { } else { }– switch (variable) { case valor: {} break; default: {} break;}
Tipos enteros : tamaños• El tamaño es dependiente de máquina y de
compilador, aunque char es siempre de 8 bits
• En el ColdFire, con el compilador GCC:– short int, signed short int, unsigned short int : 16
bits– int, signed int, long int, unsigned long int, signed
long int: 32 bits
• Las variables globales no son inicializadas nunca en el C del EdColdFire!!
Variables (asm vs. C)• 00030000 00000002 D shi• 00030002 00000004 D li• 00030006 00000004 D si• 0003000a 00000002 D sshi• 0003000c 00000004 D sli• 00030010 00000004 D ui• 00030014 00000002 D ushi• 00030016 00000004 D uli• 0003001c 00000004 B i
• 00020100 clrl 0003001c <i>• 00020106 moveq #1,%d0• 00020108 movew %d0,00030000 <shi>
• 0002010e moveq #2,%d0• 00020110 movel %d0,00030002 <li>• 00020116 clrl 00030006 <si>• 0002011c moveq #1,%d0• 0002011e movew %d0,0003000a <sshi>• 00020124 moveq #2,%d0• 00020126 movel %d0,0003000c <sli>• 0002012c clrl 00030010 <ui>• 00020132 moveq #1,%d0• 00020134 movew %d0,00030014 <ushi>• 0002013a moveq #2,%d0• 0002013c movel %d0,00030016 <uli>
• int i;• short int shi=1;• long int li=2;• signed int si=0;• signed short int sshi=1;• signed long int sli=2;• unsigned int ui=0;• unsigned short int ushi=1;• unsigned long int uli=2;
• i=0;• shi=1;• • li=2;• si=0;• sshi=1;
• sli=2;• ui=0;• • ushi=1;• uli=2;
Tipos enteros : tamaños y conversiones• Conversiones implícitas:
– Al asignar una variable de un tipo mayor a una variable de tipo menor, se recorta (bits menos significativos)• int i=0xfedbca56;• short int si=i; /* Equivale a si=0xffff */
– Al asignar una variable más pequeña a una mayor, no hay problema
– Al asignar entre variables de igual tamaño y distinto signo, no se pierden bits, pero puede variar su interpretación• signed int si=-1;• unsigned int ui;• ui=si; /* ui=65535 */
Punteros (I)• Variables que contienen una dirección de memoria• Como los registros de direcciones Ax:
– Permiten acceder indirectamente a otras variables• int i=0; /* La variable i contiene un 0 */• int *pi; /* declaración de un puntero */• pi=&i; /* El puntero pi contiene la dirección de la variable i */
• *pi=2; /* La variable i ahora contiene un 2, el puntero pi no se ve alterado */
• i=*pi; /* la variable i sigue conteniendo un 2 */
0
$XXX
i
pi
$XXX
$YYY
2
$YYY
i
pi
$XXX
$YYY
Punteros (II)• También permiten acceder a posiciones del mapa de memoria de
entrada y salida #define BASE_PUERTO_S 0x40000000
/* Direccion del puerto S */ unsigned char *puertoS=BASE_PUERTO_S; /* El puntero pi contiene la dirección del puerto de salida */
*puertoS=0xff; /* Se envía un $FF al puerto de salida */
En EdColdFire hay funciones para esta labor: Internamente usan punteros (ver m5272gpio.c)
void set16_puertoS (UWORD valor) UWORD lee16_puertoE (void)
$XX
$40000000puertoS
$40000000
$YYY
$FF
$40000000puertoS
$40000000
$YYY
variableValor de la
variablePosición
en memoria
variableValor de la
variablePosición
en memoria
Punteros (III)• Son un mecanismo de bajo nivel, peligroso
• Si no se les da un valor adecuado, pueden acceder a posiciones de memoria no deseadas:– int *pi;
• Este es un puntero que apunta a un lugar indeterminado, por no estar inicializado
– *pi=3;• Como pi puede apuntar a cualquier sitio, podemos estar
escribiendo en cualquier punto del mapa de memoria, o incluso fuera de él, (provocando un error de bus o de dirección)
Arrays (I)
– Los array son punteros constantes (no variables) que permiten acceder, de una manera indexada, a una zona de memoria reservada por el compilador automáticamente
– Dicho puntero constante equivale a la dirección de comienzo del array
– Por ser una constante, este puntero no se inicializa; se inicializa el contenido de la zona de memoria apuntada
– El índice del primer elemento es el 0, el del segundo elemento es el 1, etc.
– Es posible acceder (por error o intencionadamente) a posiciones más allá del tamaño reservado para el array
– Para copiar un array en otro es necesario copiar elemento a elemento con un bucle
Arrays (II)– int lista[3]={0,1,2}; int i=3;
• El array lista contiene 3 números, la variable i contiene un 3
– lista[1]=lista[2];• Copia el valor de la posición 2 (que es la última), en la posición 1 (que
es la segunda)
– lista[i]=0;• ERROR: modifica la variable i (situada en memoria tras el array)
2 $XXX+8 2 $XXX+8
1 $XXX+4 2
array
$XXX+4
0 $XXX 0array $XXX
3 $XXX+12 0 $XXX+12i i
Arrays (III)
• Los arrays de caracteres se suelen llamar strings.•char asignatura[4]=“SED”;•asignatura[0]=‘T’;
– Su tamaño debe ser “la longitud máxima de la cadena de caracteres” + 1, porque su último elemento es un 0 (no el carácter ‘0’).
‘D’ $XXX+2 ‘D’ $XXX+2
‘E’ $XXX+1 ‘E’
string
$XXX+1
‘S’ $XXX ‘T’string $XXX
0 $XXX+3 0 $XXX+3
Funciones (I)
• Permiten dividir un problema en subproblemas• Se implementan como subrutinas• El manejo de la pila y el uso de los registros es
automático e invisible al programador• Admiten argumentos de entrada y de salida• Suelen devolver un valor, pero no es obligatorio• Si la función no devuelve nada, al llegar a la última llave,
realiza el return automáticamente
• Todo programa en C comienza ejecutando la función llamada main, que en sistemas empotrados no suele tener argumentos de entrada o salida
Funciones (II)
• int suma(int a, int b);– Este es el prototipo de la función, que anticipa al compilador qué
argumentos admite
– Si el cuerpo de la función está antes de la llamada, el prototipo no es necesario
• void main(void){... int s=suma(10,3);... } /* S contendrá ahora un 13*/– Esta es la llamada a la función para que se ejecute, pasándole 2
parámetros compatibles con lo que establecen el prototipo y el cuerpo de la función
• int suma(int a, int b){ return a+b; }– Este es el cuerpo de la función cuya cabecera coincide con el prototipo
previo (salvo en el punto y coma final)
Tipo del valor que devuelve
Argumentos
nombre
Funciones (III)
• Una variable, pasada como parámetro a una función, no ve modificado su valor original durante la ejecución (paso por valor, copia local)
• Para modificar, dentro de una función, el valor de una variable externa a la función, debemos pasarla por referencia (pasar su dirección)– void suma(int a, int b, int *ps){*ps=a+b;}
• Por medio del puntero ps (que contiene la dirección de s), escribimos en s el resultado
– void main(void) {... int s; suma(10,3, &s );...} /* s contendrá ahora un 13*/
• Ahora se pasa la dirección de s, para que dentro de la función se pueda acceder a s
Funciones (IV)
– Los argumentos de entrada son variables locales al cuerpo de la función (aunque estén fuera de las llaves)
– Es posible definir otras variables locales– Las variables locales son temporales (se implementan como
direcciones en la pila o como registros)– El valor que se devuelve también suele ser a través de pila o
de registro• int suma(int a, int b){ int s=a+b; return s; }
– La variable local s sólo puede ser usada dentro de la función suma (ámbito). La función devuelve el contenido de s
• int * suma2(int a, int b) { int s=a+b; return &s; }
– ERROR: no se puede devolver la dirección de s, porque es local y desaparece cuando se termina de ejecutar la función
Bibliografía• Brian W. Kernighan & Dennis M. Ritchie “The C
Programming Language”, Second Edition. Prentice Hall, Inc., 1988.
• A. Clements “Microprocessor Systems Design” 3rd ed. PWS-Kent Pub. Co., 1997
• H. Schildt “C: Manual de referencia” , Ed. McGraw Hill, 1989
Recommended