Búsqueda personalizada

Anuncios Google

Entrada/Salida

Uso de funciones de alto nivel

Hay varias maneras de usar entrada/salida en ensamblador, vamos a presentar la más sencilla, usando funciones de alto nivel del lenguaje de programación C.

En C, las instrucciones básicas de entrada salida son printf y scanf, las cuales permiten respectivamente enviar (print, imprimir) o recibir (scan, leer) información.

printf

La función printf permite escribir en la salida estándar (monitor), proporcionando un formato específico para los datos a escribir.

Esta función recibe una cantidad variable de argumentos, en los que solo uno de ellos es obligatorio: la cadena de formato. Este parámetro es una cadena que permite indicar el formato que tendrá la impresión que se quiere realizar, y en base a la cual se determina la cantidad y tipo de los parámetros restantes.

Dicha cadena puede contenter caracteres comunes y corrientes, los cuales se mostrarán en pantalla exactamente como se encuentran en la cadena, y un segundo tipo de caracteres conocidos como especificadores de formato, los cuales están formados por un símbolo de porcentaje (%) y un código de formato.

Los especificadores de formato, más usados, compatibles con la función printf son los siguientes:

Especificador Formato
%c Caracter simple
%d Entero con signo en base decimal
%s Cadena de caracteres
%u Entero sin signo en base decimal
%x Entero con signo en base hexadecimal

Además de la cadena de formato, deben existir tantos parámetros adicionales como especificadores de formato contenga la cadena, ya que cada uno de los mismos proporciona el valor por el cual será sustituido cada especificador al momento de mostrar la cadena por la pantalla. Dicho de otra manera, la cadena de formato puede ser vista como una plantilla, mientras que el resto de los parámetros son los valores que completan los campos vacíos de dicha plantilla.

scanf

La función scanf permite leer desde la entrada estándar, proporcionando un formato específico para los datos a recibir. De forma análoga a la función printf, esta función permite reconocer los tipos de datos especificados por el estándar ANSI de C tales como números, caracteres y cadenas.

Los argumentos recibidos por la función scanf son similares a los de la función printf, siendo de nuevo el primero de ellos la cadena de formato. Sin embargo en este caso la cadena de formato es utilizada para especificar una "plantilla" que deberá ser completada con la entrada proporcionada por el usuario.

En este caso, por cada especificador de formato que se encuentre en la cadena será necesario proporcionar un apuntador a la dirección de memoria en la que será almacenado el elemento reconocido. Los especificadores de formato compatibles con la función scanf son los mismos que para printf.

Acerca de los argumentos

Una diferencia importante entre las funciones printf y scanf consiste en la manera en que se les pasan los argumentos. Todos los argumentos de una llamada a la función scanf (a excepción de la cadena de formato) son pasados por referencia, es decir, se proporciona la dirección de la variable y no su valor. Esto se debe a que la función utiliza estas variables para almacenar un valor leido de la entrada estándar y en consecuencia necesita saber la posición de memoria en la que el mismo será almacenado.

En contraparte, la función printf no necesita conocer la dirección de las variables, sino el valor que contienen para poder escribirlo en la salida estándar. Por esta razón, todos los tipos de dato simple (enteros, caracteres, etc.) son pasados por valor. Algunas otras variables como los arreglos y las estructuras (esto incluye las cadenas ya que son arreglos de caracteres) son pasados por referencia, pero esto se debe a limitaciones del pase de parámetros por valor (ya que los parámetros se almacenan en la pila, véase el capítulo de procedimientos) y no a que la función printf necesite conocer la dirección de dichos argumentos per se.

Ejemplos de uso de printf y scanf

Para ilustrar la utilización de ambas funciones desde un programa en lenguaje ensamblador, se presentan dos ejemplos sencillos. Sin embargo es importante hacer una acotación en este punto. Cuando se hace una llamada a las funciones printf y scanf (o a cualquier otro procedimiento), el contenido de los registros %eax, %ecx y %edx corre el riesgo de ser modificado. El motivo de esto se explica en la parte de procedimientos, sin embargo, es importante tener en cuenta este hecho al momento de programar, tomando las precauciones necesarias para no perder información importante al llevar a cabo las operaciones de lectura o escritura.

Para terminar una línea de salida y hacer que el cursor pase a la línea siguiente se utiliza \n dentro del formato de salida.

Programa que pide al usuario una cadena de caracteres mediante la utilización de scanf, y luego la muestra de nuevo mediante la utilización de printf

# Programa que lee una cadena de caracteres y la muestra por pantalla
.section .data
cad1: .asciz "Por favor introduzca una cadena: "
cad2: .asciz "%s"
cad3: .asciz "La cadena introducida es: %s\n"
.section .bss
cadena: .space 50 # Reserva espacio para la cadena introducida
.section .text
.globl _start
_start:
# Muestra un mensaje solicitando que se escriba una cadena
leal cad1, %eax # Carga la dirección de la cadena de formato
pushl %eax # Pasa el primer argumento (cad1)
call printf # Hace la llamada a printf
addl $4, %esp # Libera el espacio de la pila ocupado por el argumento
# Lee la cadena introducida por el usuario
leal cadena, %eax # Carga la dirección donde se almacenará la cadena
pushl %eax # Pasa el segundo argumento (cadena)
leal cad2, %eax # Carga la dirección de la cadena de formato
pushl %eax # Pasa el primer argumento (cad2)
call scanf # Hace la llamada a scanf
addl $8, %esp # Libera los 8 bytes de pila ocupados por los argumentos
# Muestra el resultado
leal cadena, %eax # Carga la dirección de la cadena leida
pushl %eax # Pasa el segundo argumento (cadena)
leal cad3, %eax # Carga la dirección de la cadena de formato
pushl %eax # Pasa el primer argumento (cad3)
call printf # Hace la llamada a printf
addl $8, %esp # Libera los 8 bytes de pila ocupados por los argumentos
# Finalización
movl $1, %eax # fin del programa
movl $0, %ebx
int $0x80

Programa que pide al usuario dos números enteros en notación decimal y muestra la suma de ambos

# Programa que lee dos numeros y muestra su suma
.section .data
cad1: .asciz "Valor de A: "
cad2: .asciz "Valor de B: "
cad3: .asciz "El valor de A+B es: %d\n"
cad4: .asciz "%d"
.section .bss
A: .space 4 # Reserva espacio para un entero
B: .space 4 # Reserva espacio para un entero
C: .space 4 # Reserva espacio para un entero
.section .text
.globl _start
_start:
# Muestra un mensaje solicitando el valor de A
leal cad1, %eax # Carga la dirección de la cadena de formato
pushl %eax # Pasa el primer argumento (cad1)
call printf # Hace la llamada a printf
addl $4, %esp # Libera los 4 bytes de pila ocupados por el argumento
# Lee el valor de A
leal A, %eax # Carga la dirección donde se almacenará el entero
pushl %eax # Pasa el segundo argumento ( dirección de A)
leal cad4, %eax # Carga la dirección de la cadena de formato
pushl %eax # Pasa el primer argumento (cad4)
call scanf # Hace la llamada a scanf
addl $8, %esp # Libera los 8 bytes de pila ocupados por los argumentos
# Muestra un mensaje solicitando el valor de B
leal cad2, %eax # Carga la dirección de la cadena de formato
pushl %eax # Pasa el primer argumento (cad2)
call printf # Hace la llamada a printf
addl $4, %esp # Libera los 4 bytes de pila ocupados por el argumento
# Lee el valor de B
leal B, %eax # Carga la dirección donde se almacenará el entero
pushl %eax # Pasa el segundo argumento (dirección de B)
leal cad4, %eax # Carga la dirección de la cadena de formato
pushl %eax # Pasa el primer argumento (cad4)
call scanf # Hace la llamada a scanf
addl $8, %esp # Libera los 8 bytes de pila ocupados por los argumentos
# Suma los números y deja el resultado en C
movl A, %eax
addl B, %eax
movl %eax, C
# Muestra el resultado
pushl C # Pasa el segundo argumento (C)
leal cad3, %eax # Carga la dirección de la cadena de formato
pushl %eax # Pasa el primer argumento (cad3)
call printf # Hace la llamada a printf
addl $8, %esp # Libera los 8 bytes de pila ocupados los argumentos
# Finalización
movl $1, %eax # fin del programa
movl $0, %ebx
int $0x80