Bienvenidos sean a este post, hoy hablaremos sobre una funcion que hemos utilizado anteriormente.
Este metodo es el utilizado para mostrar en pantalla lo que necesitemos, desde el resultado de una funcion hasta mensajes de texto y otros, a medida que lo ibamos usando vimos algunas formas de como formatear el contenido a mostrar pero siempre utilizamos este formato basico:
%<numero de digitos><tipo de dato>
%2d
Esta es su forma mas basica pero en realidad se compone de la siguiente forma:
%<flag><tamaño min. campo><precision><modificador tamaño><tipo de dato>
Pasemos a comentar cada uno de los posibles modificadores que podemos usar, en este caso para flag podemos usar los siguientes:
- -, alinea para la izquierda, en caso de omitirse se alinea para la derecha automaticamente
- +, es la encargada de mostrar el signo positivo o negativo de un valor, o un espacio para un signo negativo
- 0, cero-relleno
- #, una variante de formateo y dependera del tipo de dato que utilicemos
El segundo modificador sera el encargado de establecer el tamaño minimo del campo que asignaremos para mostrar el dato, este tiene que ser un valor de tipo entero, por ejemplo en el caso anterior pasamos un 2 para indicar que utilizara dos espacios para mostrar los digitos, el siguiente modificador es de precision, es decir la cantidad de digitos que mostraremos despues de la coma decimal, recuerden que esto esta basado en el sistema ingles y utilizan el punto para los decimales, para ello debemos poner un punto seguido de un valor entero para indicar cuantos digitos mostraremos, por ejemplo .4 mostrara hasta cuatro digitos decimales, el siguiente modificador sera para establecer el tamaño del tipo, veamos los disponibles:
- Long, se puede pasar como l o L, tambien acepta para LL (Long-Long)
- Short o byte, se puede pasar como h o hh
- Tipos especificos, estos se pueden pasar como j, z o t para los tipos enteros
Por ultimo especificaremos el tipo de dato que mostraremos o convertiremos, veamos los que podemos utilizar:
- Para enteros sin signo (unsigned integer), podemos pasar d, i, o, u, x, X
- Apuntadores, podemos pasar n o p
- Enteros con signo (signed integer), para este caso podemos pasar d o i
- Punto flotante, para ello podemos pasar a, A, e, E, f, F, g, G
- Caracter, cuando es un solo caracter pasamos c
- Cadena, cuando es mas de un caracter o un texto pasamos s
- Por ultimo podemos usar a % para mostrar el caracter en si
Con todo esto comentado vamos a realizar un ejemplo para ver las distintas opciones que comentamos anterriormente, para ello debemos crear un nuevo archivo que llamaremos ejemplo29.c y le agregaremoe el siguiente codigo:
ejemplo29.c
#include <stdio.h>
int main()
{
int entChico = 12;
int entGrande = (1024*1024*3)+(1024*2)+512+128+64+32+16+8+4+2+1;
int entNegativo = -entChico;
unsigned unoSinSigno = 130;
}
Estas seran algunas de las variables que usaremos en el resto del codigo, observen que tenemos varios tipos de enteros:
- El primero es uno normal y chico
- El segundo es uno bastante largo
- El tercero es el primero pero en negativo
- El ultimo es uno sin signo
Ahora vamos a comenzar con las distintas formas de printf que utilizaremos para ver sus distintas salidas, para ello despues de las variables agregaremos el siguiente segmento de lineas::
printf("Modif.\t%%#o\t\t%%#u\t\t%%#x\t\t%%#X\n");
printf("\t[%#12o]\t[%#12u]\t[%#12x]\t[%#12X]\n",
entChico, entChico, entChico, entChico);
printf("\t[%#12o]\t[%#12u]\t[%#12x]\t[%#12X]\n",
entGrande, entGrande, entGrande, entGrande);
printf("\t[%#12o]\t[%#12u]\t[%#12x]\t[%#12X]\n\n",
unoSinSigno, unoSinSigno, unoSinSigno, unoSinSigno);
En este primer segmento vamos a mostrar los valores de tres las variables que definimos al comienzo en distintas bases y por el momento sin signos, las tres primeras lineas son las que usaremos para identificar que sera cada valor que mostraremos en pantalla, uso el operador \t para hacer una tabulacion horizontal y ubicarlos de mejor forma a los distintos elementos, si observen indicamos las distintas bases que usaremos asi como su nombre, la cuarta linea sera la encargada de mostrar cual modificador estamos utilizando para mostrar cada base, vamos a tomar la quinta linea de ejemplo:
printf("\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
entChico, entChico, entChico, entChico);
Si recuerdan lo que esta entre comillas se mostrara en pantalla, en este caso entre cada corchete pusimos un modificador y cada uno de ellos estara serparado por un tabulador horizontal, en todos los modificadores le pasamos un tamaño de 12 elementos a mostrar, pero en cada uno usaremos una base distinta, siendo el primero para la base octal (base-8), la segunda una base decimal pero en este caso sin signo (unsigned), luego dos para la base hexadecimal pero en el primer caso para mostrar en minuscula y en el segundo caso en mayuscula, despues por medio de comas pasamos la variable entChico cuatro veces para que sea asignada a cada modificador, esto lo volvemos a repetir dos veces mas pero con las variables entGrande y unoSinSigno, pasemos a agregar el siguiente segmento de lineas despues del anterior:
printf("Modif.\t%%#o\t\t%%#u\t\t%%#x\t\t%%#X\n");
printf("\t[%#12o]\t[%#12u]\t[%#12x]\t[%#12X]\n",
entChico, entChico, entChico, entChico);
printf("\t[%#12o]\t[%#12u]\t[%#12x]\t[%#12X]\n",
entGrande, entGrande, entGrande, entGrande);
printf("\t[%#12o]\t[%#12u]\t[%#12x]\t[%#12X]\n\n",
unoSinSigno, unoSinSigno, unoSinSigno, unoSinSigno);
Este es exactamente igual al bloque anterior, en la parte encargada de mostrar los valores, pero en los modificadores agregamos la opcion de # para que nos muestre una variante de los distintos tipos que especificamos, con esto comentado podemos pasar a compilarlo y ver como es su salida:
tinchicus@dbn001vrt:~/lenguajes/C$ ./prog/ejemplo29
printf con enteros sin signo
Base Base-8 Base-10 Base-16 BASE-16
Nombre octal unsigned hexadecimal HEXADECIMAL
Modif. %12o %12u %12x %12X
[ 14] [ 12] [ c] [ C]
[ 14005377] [ 3148543] [ 300aff] [ 300AFF]
[ 202] [ 130] [ 82] [ 82]
Modif. %#o %#u %#x %#X
[ 014] [ 12] [ 0xc] [ 0XC]
[ 014005377] [ 3148543] [ 0x300aff] [ 0X300AFF]
[ 0202] [ 130] [ 0x82] [ 0X82]
tinchicus@dbn001vrt:~/lenguajes/C$
Observen como mediante esta forma podemos convertir valores a distintas bases con extrema facilidad, si observan en la salida del primer bloque tenemos directamente el valor de cada base pero para el caso de octal y hexadecimal para la salida del segundo bloque nos muestra un formato distinto gracias a la opcion de # que agregamos, tambien observen como varia el tamaño de las letras del valor que devuelve en base a si pasamos x o X, con esto comentado vamos a agregar el siguiente segmento de codigo despues del anterior:
printf("Numeros negativos como Unsigned:\n\n");
printf("-0\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
-0, -0, -0, -0);
printf("-1\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
-1, -1, -1, -1);
printf("-2\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
-2, -2, -2, -2);
printf("-12\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
entNegativo, entNegativo, entNegativo, entNegativo);
En este caso representaremos a numeros negativos como unsigned para ver el resultado, la primera linea sera la etiqueta para identificarlo en la salida, al igual que en el caso anterior tomemos una linea de ejemplo:
printf("-0\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
-0, -0, -0, -0);
Aqui haremos algo similar a lo anterior donde tenemos los mismos modificadores pero al comienzo indicaremos cual es el valor que mostraremos seguido de los modificadores, en este caso pasamos el valor negativo literal para cada modificador, esto mismo lo hacemos en las siguientes dos lineas pero en la ultima linea usaremos a nuestra variable negativa, para cada uno de los casos, con esto comentado compilemos y veamos como es la nueva salida:
...
Numeros negativos como Unsigned:
-0 [ 0] [ 0] [ 0] [ 0]
-1 [ 37777777777] [ 4294967295] [ ffffffff] [ FFFFFFFF]
-2 [ 37777777776] [ 4294967294] [ fffffffe] [ FFFFFFFE]
-12 [ 37777777764] [ 4294967284] [ fffffff4] [ FFFFFFF4]
tinchicus@dbn001vrt:~/lenguajes/C$
Tendremos la salida de los dos segmentos anteriores pero ahora tambien tendremos esta salida, la cual es la que queremos analizar, si observan en el primer caso al ser un valor de cero no fue afectado por el signo, en los otros casos no tenemos el resultado esperado porque cada ordenador los maneja de forma distinta, dado que utiliza un algoritmo llamado complemento de a dos, esto es asi porque nos evita tener el conflicto +0 y -0, y por definicion propia los sin signo no poseen ese bit de signo haciendo que nos devuelva su representacion interna por lo cual podemos decir que la funcion toma un patron de bits del valor informado y lo formatea al tipo de conversion informado, dejando toda la responsabilidad en nosotros para que sea mostrado de forma significativa, nuestro siguiente paso sera agregar el siguiente segmento de instrucciones:
printf("\nPotencias de 9: 9^1, 9^2, 9^3, 9^4\n");
printf("Modif.\t%%12o\t\t%%12u\t\t%%12x\t\t%%12X\n");
int k = 9;
for(int i=0; i < 4; i++, k*=9)
{
printf("\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
k, k, k, k);
}
Las primeras dos lineas seran para identificar las acciones y las etiquetas que representa cada resultado, lo siguiente sera definir una variable que sera la utilizada para elevar en distintas potencias, por ultimo tendremos un bucle que se repetira cuatro veces y por cada pasada elevaremos la potencia del valor en k, dentro mostraremos en los distintos tipos que vinimos utilizando cada uno de los nuevos valores de k, con esto comentado compilemos y veamos la nueva salida:
....
Potencias de 9: 9^1, 9^2, 9^3, 9^4
Modif. %12o %12u %12x %12X
[ 11] [ 9] [ 9] [ 9]
[ 121] [ 81] [ 51] [ 51]
[ 1331] [ 729] [ 2d9] [ 2D9]
[ 14641] [ 6561] [ 19a1] [ 19A1]
tinchicus@dbn001vrt:~/lenguajes/C$
Volveremos a tener los valores anteriores de los segmentos anteriores pero al final obtendremos los nuevos valores del bloque agregado recientemente, en este caso iremos incrementando el valor de 9 y vemos como se convierte en los distintos tipos de datos, por ultimo vamos a agregar este segmento de instrucciones despues del anterior:
printf("\nMostrando un apuntador:\n");
printf(" %%p\t[%p]\tapuntador\n", &entChico);
printf(" %%#lx\t[%#lx]\tUsando Hex\n", (unsigned long)&entChico);
En este caso mostraremos un apuntador, si lo usamos directamente por medio del modificador p no es necesario hacer ninguna tarea adicional sino simplemente pasarlo y la instruccion se encargara de mostrar la direccion de memoria de 64 bits, en cambio para la segunda opcion al mostrarlo en Hexadecimal debemos utilizar la opcion de Long (l) junto a la de hexadecimal, para representar la direccion de 64bits, y en este caso si debemos castearlo (unsigned long) porque de lo contrario nos devolvera un error al compilarlo, con esto comentado vamos a ver como quedo el codigo final de nuestro archivo:
ejemplo29.c
#include <stdio.h>
int main()
{
int entChico = 12;
int entGrande = (1024*1024*3)+(1024*2)+512+128+64+32+16+8+4+2+1;
int entNegativo = -entChico;
unsigned unoSinSigno = 130;
printf("printf con enteros sin signo\n\n");
printf("Base\tBase-8\t\tBase-10\t\tBase-16\t\tBASE-16\n");
printf("Nombre\toctal\t\tunsigned\thexadecimal\tHEXADECIMAL\n");
printf("Modif.\t%%12o\t\t%%12u\t\t%%12x\t\t%%12X\n");
printf("\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
entChico, entChico, entChico, entChico);
printf("\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
entGrande, entGrande, entGrande, entGrande);
printf("\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n\n",
unoSinSigno, unoSinSigno, unoSinSigno, unoSinSigno);
printf("Modif.\t%%#o\t\t%%#u\t\t%%#x\t\t%%#X\n");
printf("\t[%#12o]\t[%#12u]\t[%#12x]\t[%#12X]\n",
entChico, entChico, entChico, entChico);
printf("\t[%#12o]\t[%#12u]\t[%#12x]\t[%#12X]\n",
entGrande, entGrande, entGrande, entGrande);
printf("\t[%#12o]\t[%#12u]\t[%#12x]\t[%#12X]\n\n",
unoSinSigno, unoSinSigno, unoSinSigno, unoSinSigno);
printf("Numeros negativos como Unsigned:\n\n");
printf("-0\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
-0, -0, -0, -0);
printf("-1\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
-1, -1, -1, -1);
printf("-2\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
-2, -2, -2, -2);
printf("-12\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
entNegativo, entNegativo, entNegativo, entNegativo);
printf("\nPotencias de 9: 9^1, 9^2, 9^3, 9^4\n");
printf("Modif.\t%%12o\t\t%%12u\t\t%%12x\t\t%%12X\n");
int k = 9;
for(int i=0; i < 4; i++, k*=9)
{
printf("\t[%12o]\t[%12u]\t[%12x]\t[%12X]\n",
k, k, k, k);
}
printf("\nMostrando un apuntador:\n");
printf(" %%p\t[%p]\tapuntador\n", &entChico);
printf(" %%#lx\t[%#lx]\tUsando Hex\n", (unsigned long)&entChico);
}
Ahora si con todo esto comentado procedamos a compilarlo para ver su salida final:
tinchicus@dbn001vrt:~/lenguajes/C$ ./prog/ejemplo29
printf con enteros sin signo
Base Base-8 Base-10 Base-16 BASE-16
Nombre octal unsigned hexadecimal HEXADECIMAL
Modif. %12o %12u %12x %12X
[ 14] [ 12] [ c] [ C]
[ 14005377] [ 3148543] [ 300aff] [ 300AFF]
[ 202] [ 130] [ 82] [ 82]
Modif. %#o %#u %#x %#X
[ 014] [ 12] [ 0xc] [ 0XC]
[ 014005377] [ 3148543] [ 0x300aff] [ 0X300AFF]
[ 0202] [ 130] [ 0x82] [ 0X82]
Numeros negativos como Unsigned:
-0 [ 0] [ 0] [ 0] [ 0]
-1 [ 37777777777] [ 4294967295] [ ffffffff] [ FFFFFFFF]
-2 [ 37777777776] [ 4294967294] [ fffffffe] [ FFFFFFFE]
-12 [ 37777777764] [ 4294967284] [ fffffff4] [ FFFFFFF4]
Potencias de 9: 9^1, 9^2, 9^3, 9^4
Modif. %12o %12u %12x %12X
[ 11] [ 9] [ 9] [ 9]
[ 121] [ 81] [ 51] [ 51]
[ 1331] [ 729] [ 2d9] [ 2D9]
[ 14641] [ 6561] [ 19a1] [ 19A1]
Mostrando un apuntador:
%p [0x7ffdd3e1adb8] apuntador
%#lx [0x7ffdd3e1adb8] Usando Hex
tinchicus@dbn001vrt:~/lenguajes/C$
Hasta aqui hemos visto como podemos manejar la salida de unos valores de tipo entero sin signo pero que sucede con el resto, eso lo iremos viendo en los proximos posts, asi que sigan sintonizados en este mismo blog. 😉
En resumen, hoy hemos visto a printf, como se compone, como son sus modificadores para poder dar un formato a la informacion que le pasemos, despues vimos un ejemplo donde pasarmos por distintas variantes de como manejar un valor entero sin signo (unsigned), espero les haya sido de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donación
Es para mantenimento del sitio, gracias!
$1.50
