Lab 1 - Introducción a C¶
Objetivos¶
- Aprender cómo compilar y ejecutar un programa en C.
- Examinar diferentes tipos de control de flujo en C.
- Ganar experiencia manipulando bits
Preparación¶
Para obtener sus archivos base visite el siguiente link.
https://classroom.github.com/a/SMs9QGdc
Allí debe aceptar la asignación para que su repositorio sea creado. Al hacerlo, tendrá un repositorio con un link como este.
https://github.com/cc3-ug/lab01-2025-MI_USUARIO.git
Abra una terminal y navegue en ella hacia el lugar donde quiera colocar su laboratorio. Como es la primera vez que traeremos información del remote hacia nuestra computadora, usaremos el comando clone. Recuerde cambiar MI_USUARIO
por su usuario.
git clone https://github.com/cc3-ug/lab01-2025-MI_USUARIO.git
Al ejecutar el comando Github le pedirá su "contraseña", sin embargo desde hace un par de años ya no acepta contraseñas sino tokens, genere el suyo siguiendo los pasos que se indican en esta página. Puede usar el mismo token de la semana pasada (bueno... depende de la fecha de vencimiento que le haya colocado)
https://docs.github.com/es/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token
Tras haber realizado el clone exitosamente, tendrá en su máquina una carpeta con todos los archivos que usaremos en este lab.
Recordatorio: compilar y ejecutar un programa de C¶
En este laboratorio, estaremos usando el programa gcc
para compilar programas en c. La manera más sencilla de ejecutar gcc
es la siguiente:
gcc program.c
program.c
y crea un archivo ejecutable llamado a.out
. Si tienen experiencia en Java, pueden más o menos considerar a gcc
como el equivalente en C de javac
. Este archivo se puede ejecutar con el siguiente comando:
./a.out
a.out
, así que, ¿qué rayos es eso de punto y diagonal? La respuesta: cuando quieren ejecutar un ejecutable, es necesario preponer una ruta de archivo para distinguirlo de un comando como python
(no se utiliza ./python
). El punto se refiere al "directorio actual". De paso, dos puntos (..) se referirían al directorio que está un nivel arriba.
gcc
tiene varias opciones (o argumentos) de línea de comandos, los cuales les recomendamos explorar. En este laboratorio, vamos a estar usando solamente -o, que se usa para especificar el nombre del ejecutable que gcc
genera. Usando -o, se utilizarían estos comandos para compilar program.c
en un archivo llamado program
, y ejecutarlo. Eso nos sirve si no queremos que todos nuestros archivos ejecutables se llamen a.out
.
gcc -o program program.c ./program
Ejercicio 1: Operando bits¶
Para este inciso, su trabajo es completar los archivos ex1/get_bit.c, ex1/set_bit.c y ex1/flip_bit.c de manera que las funciones cumplan con la tarea que su nombre indica (obtener un bit, actualizar el valor de un bit, negar un bit). Para ello deberán utilizar las operaciones de bits básicas: and (&), or (|), xor (^), not (~) y los corrimientos a la derecha (>>) y a la izquierda (<<). Lea la sección 2.9 de K&R si aún no ha llegado.
Para este ejercicio no pueden utilizar condicionales ni ciclos. Es decir, no escriba ningún if, else, do, while, for, switch o case. No intente engañarnos, revisaremos que no los use.
El autograder analiza su código de todas formas...
NOTA IMPORTANTE: Considerar que n es un valor que inicia en la posición cero. Su bit menos significativo (es decir hasta la derecha) es el bit 0, y su bit más significativo (es decir hasta la izquierda) sería su bit 31.
// Return the nth bit of x. // Assume 0 <= n <= 31 unsigned get_bit(unsigned x, unsigned n); // Set the nth bit of the value of x to v. // Assume 0 <= n <= 31, and v is 0 or 1 void set_bit(unsigned * x, unsigned n, unsigned v); // Flip the nth bit of the value of x. // Assume 0 <= n <= 31 void flip_bit(unsigned * x, unsigned n);
x & 0 = 0 x & 1 = x x | 0 = x x | 1 = 1
Aproveche una o varias de estas propiedades para escribir en la casilla deseada.
Idea para flip_bit(): ¿Habrá otra operación bitwise con propiedades similares al and y or que aún no haya usado? Quizás hay alguna que me haga la tarea...
Una vez terminen de editar las funciones, pueden compilar y correr el código con:
make bit_ops ./bit_ops
Ahora estamos usando un Makefile, el cuál tiene dentro comandos que nos facilitan la compilación. Al ejecutar ./bit_ops
se imprimirá el resultado de algunas pruebas. Si tienen curiosidad pueden revisar con libertad la carpeta tests que contiene las pruebas que se van a realizar en cada ejercicio de este laboratorio y que reflejan bastante lo que evaluará el autograder, por ejemplo el archivo que se utiliza para este ejercicio es tests/bit_ops_test.c.
Al terminar su ejercicio recuerde hacer add + commit + push hacia Github.
Ejercicio 2: Registro de Corrimiento con Retroalimentación Lineal¶
En este ejercicio deben de implementar una función que compute la siguiente iteración de un registro de corrimiento de retroalimentación lineal (Left Feedback Shift Register, LFSR por sus siglas en inglés).
Algunas aplicaciones que utilizan LFSRs son: televisión digital, teléfonos con acceso múltiple por división de código, Ethernet, USB 3.0 y mucho más.
Esta función deberá generar números pseudo-aleatorios utilizando operadores binarios. Si quiere conocer un poco más, puede visitar el siguiente link de Wikipedia.
En el archivo ex2/lfsr_calculate.c deben de completar la función lfsr_calculate() de manera que realice lo siguiente:
Diagrama del hardware¶
Explicación del diagrama¶
- En cada llamada de
lfsr_calculate()
deben de correr el contenido del registro un bit hacia la derecha. - Este corrimiento no es el lógico ni aritmético que ya conoce, sino que en el lado izquierdo deben de colocar un bit equivalente a un XOR de los bits que estaban, originalmente, en las posiciones 1, 3, 4 y 6.
- El objeto que parece un faro de automóvil curvado es un XOR, el cual recibe dos entradas (a, b) y devuelve en su salida a^b.
- A diferencia del ejercicio 1, las posiciones de los bits inician con 1.
Después que hayan implementado de manera correcta lfsr_calculate()
, compilen y córranlo. Su respuesta debe ser similar a lo siguiente:
make lfsr ./lfsr My number is: 1 My number is: 5185 My number is: 38801 My number is: 52819 My number is: 21116 My number is: 54726 My number is: 26552 My number is: 46916 My number is: 41728 My number is: 26004 My number is: 62850 My number is: 40625 My number is: 647 My number is: 12837 My number is: 7043 My number is: 26003 My number is: 35845 My number is: 61398 My number is: 42863 My number is: 57133 My number is: 59156 My number is: 13312 My number is: 16285 ... etc etc ... Got 65535 numbers before cycling! Congratulations! It works!
Ejercicio 3: Concatenando bits¶
Para este ejercicio implementaremos una función que concatena los bits de dos números:
unsigned concat_bits(unsigned x, unsigned len_x, unsigned y, unsigned len_y)
Cuyos parámetros representan:
x
: Al concatenar, este número quedará antepuesto al otroy
: Al concatenar, este número quedará después, quedará en las posiciones menos significativaslen_x
: Enx
nos llegarán 32 bits (porque es un int), pero no consideraremos como "útil" todo el número, para la concatenación tomaremos en cuenta solo loslen_x
bits menos significativos, lo demás lo ignoraremoslen_y
: De igual manera paray
, solo tomaremos en cuenta loslen_y
bits menos significativos, lo demás lo ignoraremos
Después de concatenar, debe ver si su "pedacito de número" parece negativo o positivo y rellenar las posiciones más significativas con el valor correspondiente.
Ejemplo 1¶
Nos envian 0x000000aa con longitud 8, y 0x0000cccc con longitud 16Nos interesan los 8 bits menos significativos de 0x000000aa, es decir 0xaa Nos interesan los 16 bits menos significativos de 0x0000cccc, es decir 0xcccc
Concatenamos y nos va quedando 0xaacccc
Finalmente nos damos cuenta que parece negativo (al convertir a binario se mira como 1010 1010 1100...) entonces rellenamos las casillas faltantes con 1s Nuestro resultado final es 0xffaacccc
Ejemplo 2¶
Nos envian 0x00000066 con longitud 6, y 0xfffffccc con longitud 10Nos interesan los 6 bits menos significativos de 0x00000066, es decir 0x26 (Fijese bien... 0x00000066 se mira como ...0000 0000 0110 0110 Cuando me piden tomar solo 6 bits, tomamos 10 0110, lo cual se mira como 0x26)
Nos interesan los 10 bits menos significativos de 0xfffffccc, es decir 0x0cc (Fijese bien... 0xfffffccc se mira como ...1111 1100 1100 1100 Cuando me piden tomar solo 10 bits, tomamos 00 1100 1100, lo cual se mira como 0x0cc)
Al concatenar, estaremos uniendo 10 0110 con 00 1100 1100 Nos quedara 1001100011001100 Que en grupos de cuatro se ve 1001 1000 1100 1100, es decir 0x98cc
Finalmente nos damos cuenta que parece negativo (al convertir a binario se mira como 1001 1000...) entonces rellenamos las casillas faltantes con 1s Nuestro resultado final es 0xffff98cc
Probamos este ejercicio usando:
make concat_bits ./concat_bits
Entrega de laboratorio¶
Antes de entregar, podemos revisar cuántos puntos obtendremos usando el autograder que se nos provee.
Si está en su propio Linux instale lo siguiente. Si está en la máquina virtual del curso, no es necesario, esto ya venía instalado.
pip3 install --upgrade pip pip3 install tabulate psutil pycparser
Ahora ya podemos usar el autograder. Vaya a la carpeta de su laboratorio, y ejecute:
./check
Al hacerlo verá algo parecido a lo siguiente:
___ __ __ / _ |__ __/ /____ ___ _______ ____/ /__ ____ / __ / // / __/ _ \/ _ \/ __/ _ \/ _ / -_) __/ /_/ |_\_,_/\__/\___/\_, /_/ \_,_/\_,_/\__/_/ /___/ Machine Structures Great Ideas in Computer Architecture Intro to C Exercise Grade Message ------------ ------- -------------------------------------- 2. bit_ops 35 passed 3. lfsr 30 passed 4. concat_bits 35 passed
La nota que aparezca allí es la nota que obtendrá en su laboratorio. En este lab, las series valen 35, 30 y 35 respectivamente.
Cuando esté conforme con su nota (¡apúntele siempre al cien!), entregue su laboratorio a través de Github (los add
, commit
y push
que se le pidieron arriba).
Luego envíe el link de su repositorio de Github en el GES. El GES tiene una opción para enviar links, ÚSELA. No vaya a poner su link en un txt, pdf, etc. Si lo hace, su lab no será calificado.