Archivo

Archivo para Abril, 2010

El lenguaje C en primera posición [de nuevo]

Jueves, 29 de Abril de 2010 Gaspar Fernández Sin comentarios

tiobeLeo en el Blog de Manuel Pereira que a su vez lee en Mi visión la nueva actualización del índice TIOBE.
En el que el lenguaje C vuelve a estar en primera posición con respecto a Java, que lo ha dejado en segundo lugar durante muchos años, y junto con C++ (aunque PHP sigue de cerca) forman el podio.

Aunque, en muchos centros de enseñanza se considere que C o C++ son lenguajes anticuados, podemos ver que están a la orden del día y de hecho son usados, y mucho. Eso me hace plantearme la forma en la que se enseña C en muchos sitios, algún día comentaré mi opinión de este tema.

El índice TIOBE se genera cada mes y se forma haciendo consultas en los buscadores más populares, por tanto, veremos los lenguajes más populares en este momento, es un punto a considerar a la hora de iniciar un nuevo proyecto de programación; para más información ver la web oficial.

Cosas que damos por hechas en C/C++: int main(int argc, char *argv[])

Martes, 27 de Abril de 2010 Gaspar Fernández Sin comentarios

Esta serie de posts está dedicada a tod@s mis alumn@s de clases particulares de programación. Iré añadiendo información de diferentes niveles, dificultades, colores y sabores. Espero que les parezca interesante.

Fue en el primer año de carrera, cuando en la asignatura Fundamentos de Programación y luego en Laboratorio de Programación cuando empezábamos a hacer los primeros programas en C; yo hasta entonces no me había atrevido a programar nada en C, prefería Pascal, al menos llegué con una buena base de programación.

El IDE que utilizábamos (Dev-C++) directamente escribía las primeras líneas de programa:

#include

using namespace std;

int main(int argc, char *argv[])
{

}

Comprendo que en 4 meses hay que enseñar a mucha gente a defenderse con la programación, y no es objeto explicarlo todo detalladamente, aunque cuando alguien preguntaba siempre decían: “Eso hay que ponerlo siempre” es más, nada más empezar el curso, poca gente se va a enterar de qué va el asunto

Bien, empezamos por el include (vale, esto sí que lo contaban mis profesores, porque a veces teníamos que incluir alguna cosa más), incluir funciones y clases hechas por otras personas, y no nos tiene que importar cómo están hechas por dentro.

Un concepto más peliagudo y extenso es el de la línea siguiente: using namespace std (nos metemos a pelear con los espacios de nombres; no quiero ser demasiado extenso, pero imaginemos que hay dos casas en una calle, y cada casa aloja a tres personas: Jose, Virginia y Antonio en la casa A; y Alfonso, Manuela y Jose en la casa B. ¿Cómo distinguimos a Jose de la casa A de Jose de la casa B? Suena a pregunta tonta: Pues casaA::Jose y casaB::Jose, son dos personas diferentes.
Lo mismo podemos hacer en C++, podemos tener funciones que se llaman igual en espacios de nombres (o casas) diferentes, y para referirnos a ellos tenemos que decir primero en qué casa están, para que luego el compilador sepa ubicar a cada uno.
Pero como las pulsaciones de teclado de los desarrolladores son oro (sabemos que tenemos que escribir mucho, si podemos ahorrar algo mejor), y sabemos que muchas de las clases y funciones que vamos a utilizar pertenecen a la librería estándar (o std), es decir, estarán en la mansión std decimos:
using namespace std;
o lo que es lo mismo: si no te digo nada, y llamo a alguien que no encuentras, búscalo en std.

Llegamos al main(), podemos definirlo de muchas formas: muchos utilizan void main() (y gcc se queja), otros int main() (que es perfectamente válido), pero algunas veces se introduce toda esa parafernalia rara de int argc, char *argv[], que es impronunciable, y hace daño a la vista, e incluso si lo intentamos escribir las primeras veces, no nos saldrá igual.
Estos parámetros son para los argumentos del programa, es decir, para los parámetros que introduzcamos en la línea de comandos. Para muchos usuarios que vienen de Windows, les resulta raro entender por qué un programa requiere parámetros, pues bien: si abrimos Mi PC, nos vamos a una carpeta y abrimos un documento, cómo sabe Microsoft Office que hemos abierto este documento? Se lo hemos pasado como parámetro sin querer :)
Ahora bien, y esto requiere un poco de imaginación si estamos empezando:
argc es un número que indica el número de parámetros que tiene el ejecutable:

1
2
3
4
5
6
7
8
#include <stdio.h>

int main(int argc, char *argv)
{
  printf("Me has pasado: %d parámetros\n", argc);

  return 0;
}

Veamos qué pasa al ejecutarlo:

$ ./params
Me has pasado: 1 parámetros
$ ./params param1 param2 “parametro 3″
Me has pasado: 4 parámetros
$ ./params param1 param2 “parametro 3″ “parametro 4″
Me has pasado: 5 parámetros

Nos sobra uno no? Veamos cuáles son esos parámetros:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>

int main(int argc, char *argv[])
{
  int i;

  printf("Me has pasado: %d parámetros\n", argc);

  for (i=0; i<argc; i++)
    {
      printf ("Parámetro %d: %s\n",i,argv[i]);
    }

  return 0;
}

Salida:

$ ./params param1 param2 “parametro 3″ “parametro 4″
Me has pasado: 5 parámetros
Parámetro 0: ./params
Parámetro 1: param1
Parámetro 2: param2
Parámetro 3: parametro 3
Parámetro 4: parametro 4

Vemos que el parámetro 0 es el propio nombre del ejecutable y comprobamos que si cambiamos el nombre del ejecutable, podemos saberlo con ese parámetro 0. Los demás podemos averiguarlos recorriendo la variable argv. argv es un Array de punteros de tipo char o lo que es lo mismo un array de cadenas de caracteres puesto que cada parámetro es una cadena de caracteres.

Ahora la pregunta del millón, si utilizamos un array, para qué necesitamos argc ¿? Podríamos averiguar el número de elementos del mismo. La respuesta es que no, de ese Array desconocemos el número de elementos que tiene (depende de lo que nos pase el usuario), y si tenemos un método para calcular el número de parámetros que tenemos, que seguro que podremos encontrarlo, será mucho más rápido disponer de ese valor (y escribimos menos)

Cuando un proceso “se come” la memoria de nuestro sistema

Martes, 20 de Abril de 2010 Gaspar Fernández 4 comentarios

pacmanHoy en día no se le suele ver la cara, dado que la memoria de nuestro sistema suele ser grande, pero cuando por ejemplo, a un proceso se le va la mano y reserva más memoria de la que tiene nuestro sistema, entra en marcha un proceso especial del núcleo de Linux; el OOM Killer (Out Of Memory Killer), que se encarga de detectar qué proceso es el peor del sistema y matarlo.
Atendiendo a la documentación (oom_kill.c) tendremos tres opciones cuando nos quedamos sin memoria:

  • Matar un proceso al azar (malo)
  • Congelar el sistema (peor)
  • Matar un proceso de forma inteligente

En fin, si el sistema no está configurado para congelarse (sysctl.kernel_panic_on_oom), intentaremos ver qué proceso tiene más papeletas para morir (el más dañino), y se hace asignando puntuaciones a procesos, en definitiva queremos matar un proceso malo en beneficio para el sistema, no queremos fastidiar diez horas de trabajo frente al ordenador (a menos que sea necesario).

Se sigue el siguiente algoritmo:

  • Los primeros puntos a sumar son la cantidad de memoria del proceso
  • Sumamos la memoria independiente de sus procesos hijos
  • Los procesos con prioridad (nice) duplican la puntuación. Un proceso con nice si se come nuestra memoria compromete el sistema.
  • Los procesos de superusuario dividen por 4 la puntuación. Los procesos de sistema o de superusuario no deberían dar ningún problema, y si root ejecutara algo… él/ella sabe lo que hace ;)
  • Miramos el valor de /proc/ /oom_adj (comprendido entre -17 y +15). Como usuarios, podemos aumentar o disminuir la probabilidad de que un proceso salga elegido para su sacrificio (por el bien del sistema). Si escribimos en ese fichero un -17, nuestro proceso no va a matarlo nunca el OOM killer

Como buen Linux, que nos deja como usuarios poder tocar su funcionamiento, tenemos lo siguiente:

  • /proc/PID/oom_score : Puntuación de un proceso
  • /proc/PID/oom_adj : Asignar o quitar papeletas para que un proceso sea sacrificado (como dije en la lista anterior). Es buena idea que si sabemos que un proceso puede colgar nuestro sistema, le demos un +15; si el sistema se lo carga, mejor; y si es algo importante aunque nuestro sistema ande falto de memoria, le damos un -17
  • sysctl vm.panic_on_oom : En lugar de matar un proceso, lanza un kernel panic.
  • Hay más reglas para configuración si buscamos dentro de sysctl y /proc/

¿Queremos saber qué proceso tiene, ahora mismo, más papeletas para ser sacrificado?
Si disponemos de /proc/sys/vm/oom_victim lo podremos ver ahí, si no, podemos ejecutar este script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
min=0

for pid in `ps axo pid`
do
        if [ -r /proc/$pid/oom_score ]
        then
                puntos=`cat /proc/$pid/oom_score`;
                if (( $puntos > $min ))
                then
                        proceso=$pid;
                        min=$puntos;
                fi
        fi
done

ps ax | grep $proceso

Y lo más importante, queremos lanzarlo a mano, es decir, hay un proceso gastando mucha memoria y procesador, tanta, que no podemos hacer login en el sistema desde consola. Podemos hacer: Alt + SysRq + F y saltará un OMM Manual (Si sysctl kernel.sysrq = 1), es normal que se muera Firefox :) (gasta muchos recursos y Linux lo considera dañino para el sistema)

Foto: Joe Shlabotnik (Flickr)

Por qué no debemos utilizar gets()

Lunes, 19 de Abril de 2010 Gaspar Fernández 3 comentarios

A veces me sorprendo (como profesor de programación) de que en muchos sitios siguen enseñando la función gets() para la entrada de datos desde teclado sin explicar lo que puede pasar.

gets() es una función peligrosa. Imaginemos que escribimos el siguiente programa:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main()
{
  char cadena2[10];
  char cadena1[10];

  printf("c1: %x\nc2: %x\n", cadena1, cadena2);
  gets(cadena1);

  printf("Cadena 2: %s\n", cadena2);
}

Ahora la compilamos, ejecutamos e introducimos un texto de prueba:

$ gcc -o test3 test3.c
/tmp/ccK2P2ON.o: In function `main’:
test3.c:(.text+0×32): warning: the `gets’ function is dangerous and should not be used.
$ ./test3
c1: bfc81580
c2: bfc8158a
Escribo un texto de mas de 10 caracteres
Cadena 2: texto de mas de 10 caracteres
Violación de segmento

Ya de primeras nos avisa gcc de que la función no debería ser usada, a lo que muchos se sorprenden.
Luego, en la ejecución, tal como se indica en el código fuente, mostramos las direcciónes de memoria donde se ubicarán cadena1 (c1) y cadena2 (c2).
Tras ello escribimos: “Escribo un texto de mas de 10 caracteres“, que se introducirá en la variable cadena1 y mostramos la variable cadena2, que muestra parte de lo que escribimos antes… y además de regalo una violación de segmento, porque nuestro programa ha escrito en una región de memoria que no le pertenecía.

Todo esto sucede porque gets() no tiene ninguna manera de saber cuánto puede escribir, y por ello, escribirá siempre en memoria, todos los caracteres que introduzcamos (para un ejemplo rápido vale, pero ya), de todas formas no debemos darlo todo por perdido, tenemos una excelente función, muy parecida fgets(), aunque tiene más parámetros:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

#define MAX_LON_CADENA 10

int main()
{
  char cadena2[MAX_LON_CADENA];
  char cadena1[MAX_LON_CADENA];

  printf("c1: %x\nc2: %x\n", cadena1, cadena2);

/*   gets(cadena1); */
  fgets(cadena1, MAX_LON_CADENA, stdin);
  printf("Cadena 1: \"%s\"\n", cadena1);
  printf("Cadena 2: %s\n", cadena2);
}
  1. El primer parámetro de fgets() es dónde vamos a almacenar lo leído.
  2. El segundo parámetro es cuántos caracteres leeremos como máximo (incluyendo el terminador de cadena). Y si hemos definido un valor máximo para la cadena, podemos utilizar éste.
  3. El tercero es de dónde lo leemos, y si queremos hacerlo desde teclado, usaremos stdin
Categories: C/C++ Tags: , , , , ,

Tamaño de un fichero en C

Lunes, 19 de Abril de 2010 Gaspar Fernández Sin comentarios

Veo en nosolounix un ejercicio similar. Se trata de averiguar el tamaño en bytes de un archivo (Luego podemos saber su tamaño en Kb, Mb, Gb…).

Yo propongo una solución algo más ligera (sin necesidad de recorrer el fichero para contar sus bytes), utilizando las funciones fseek y ftell para posicionarnos y averiguar la posición del puntero del fichero en un instante:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>


main ()

{

  FILE *fich;

  fich=fopen("test.c","r");

  fseek(fich, 0L, SEEK_END);
  printf("test.c ocupa %d bytes", ftell(fich));
  fclose(fich);

}
Categories: C/C++ Tags: , , , ,

Cuando Facebook hace de las suyas [ BUG CSS ]

Sábado, 17 de Abril de 2010 Gaspar Fernández Sin comentarios

Durante este año y varias veces ha habido un pequeño bug CSS que hace que los que mantenemos aplicaciones para Facebook (y no es un trabajo a tiempo completo) nos tiremos de los pelos.

Y es que al cargar nuestra aplicación, los estilos css no funcionan, no cargan, y si cargamos el archivo de Facebook del tipo:

http://external.ak.fbcdn.net/fbml_static_get.php?src=http%3A%2F%2Fmiurl.com%2Faplicacion%2Fcss%2Ffilo.css%3F_fb_q%3D1&appid=107083291268&pv=1&sig=5ee8229e4afbee29836224de876dfa&filetype=css

nos devolverá un precioso mensaje que dice:

Parámetro no válido: Error desconocido

Lo mejor es que el mensaje está traducido al español, por lo que al principio podemos sospechar que falla nuestra aplicación y luego cuando buscamos el error lo tenemos más difícil, aunque podemos buscar lo siguiente (aparece también en inglés, según nuestra localizacion):

Invalid parameter: Unknown error

El bug aún está abierto (a día 17 de Abril de 2010): podéis consultar el estado actualizado aquí.

Pero mientras investigaba el bug, encontré un pequeño fragmento de código interesante (y podemos utilizarlo como solución temporal al problema):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function minify( $css ) {
        $css = preg_replace( '#\s+#', ' ', $css );
        $css = preg_replace( '#/\*.*?\*/#s', '', $css );
        $css = str_replace( '; ', ';', $css );
        $css = str_replace( ': ', ':', $css );
        $css = str_replace( ' {', '{', $css );
        $css = str_replace( '{ ', '{', $css );
        $css = str_replace( ', ', ',', $css );
        $css = str_replace( '} ', '}', $css );
        $css = str_replace( ';}', '}', $css );

        return trim( $css );
}

function includeStyleCSS($filename)
{
        // due to: http://bugs.developers.facebook.com/show_bug.cgi?id=9053
        // We either must print the stylesheet inline
        // or include it with a link tag that does not include rel="stylesheet".
        // Fixed 3/6/2010
        // Broken 4/13/2010:http://bugs.developers.facebook.com/show_bug.cgi?id=9601

        // use this block when linked CSS is broken
        echo "<style type=\"text/css\">";
        $content = @file_get_contents($filename);
        echo minify( $content );
        echo "</style>";

        // use this block when linked CSS is working
        //      echo "<link rel=\"stylesheet\" href=\"http://MYSERVER.COM/$filename\" type=\"text/css\" />\n";
}

He dejado el fragmento de código original, pero podemos verlo atentamente y analizar lo que hace:

  • Dentro de minify(), el primer regexp_replace elimina cuando hay más de un espacio seguido; el segundo, elimina los comentarios. Los str_replace que le siguen, sirven para eliminar espacios sobrantes cerca de caracteres de inicio y fin, y separación.
  • includeStyleCss() introduce dentro de nuestro archivo resultante el CSS del archivo (más o menos reducido por minify()).

Hay que destacar que es una medida provisional, pero es interesante incluir este código en nuestras aplicaciones porque Facebook es reincidente en este fallo y no descartamos que vuelva a ocurrir.

Pero bueno, como yo no me puedo quedar quieto, vamos a intentar mejorar este código (propuesto en la discusión del bug por Ed Holzwarth, aunque he podido encontrar algún fragmento de minify por la red.

La modificación de este código viene de un poquito de investigación por otras webs:

1
2
3
4
5
6
7
8
9
10
11
12
13
function minify($css)
{
  // Quitamos comentarios
  $css = preg_replace('#/\*.*?\*/#s', '', $css);
  // Quitamos espacios en blanco cerca de {}|:;,
  $css = preg_replace('/\s*([{}|:;,])\s+/', '$1', $css);
  // Quitamos espacio en blanco al inicio
  $css = preg_replace('/\s\s+(.*)/', '$1', $css);
  // Quitamos ; innecesarios
  $css = str_replace(';}', '}', $css);

  return $css;
}

Por cierto, sería interesante aplicar este minificador al script de cache y compresión de ficheros CSS. que publiqué hace un tiempo.

Aprovechando el return de la función main()

Viernes, 16 de Abril de 2010 Gaspar Fernández Sin comentarios

turn

Imaginamos que en la realización de nuestro shell-script utilizamos un pequeño programa que hemos hecho en C (por ejemplo) y, además de su salida por pantalla, debemos tener también otro valor de retorno (ya sea un código de error, un número de veces que se ha realizado una acción, etc). Es decir, nuestro int main() { return X; }.

Para ello tenemos este programa:

1
2
3
4
int main()
{
  return 4;
}

Lo llamamos test.c y lo compilamos:

$ gcc -o test test.c

y justo después de ejecutar el programa, debemos leer el valor de $?, lo suyo es almacenarlo en una variable, ya que cuando llamemos a otro programa, se almacenará el valor de retorno del nuevo programa:

$ ./test
$ val=$?
$ if (( $val == 2 )); then echo “DOS”; else if (( $val == 4 )); then echo “CUATRO”; fi; fi

Foto: Lel4nd (Flickr)

Categories: Bash, C/C++, Linux Tags: , , , ,

Control-D para terminar la entrada estándar (EOF stdin)

Viernes, 16 de Abril de 2010 Gaspar Fernández Sin comentarios

A veces, con muchos comandos, por ejemplo sort, tail, cat, read, o muchos otros programas que leen datos de un fichero que luego procesan, tenemos la necesidad de utilizarlos con la entrada estándar del sistema, ya sea para hacer una prueba rápida, evitar tener que escribir un fichero o cualquier otra cosa.

Pero podemos estar introduciendo texto para esos comandos de forma indefinida:

$sort
estrella
mar
troglodita
alienígena
carpa
kiosko
gatillo

¿La forma de dejar de introducir texto? Control-D es un EOF de la stdin para el comando en cuestión que estemos ejecutando.

Eso sí, Control-D, también vale para cerrar la sesión, y si nos aficionamos mucho a utilizarlo, tal vez nos llevemos algún disgusto si la pulsamos cuando no debemos. Para ello podemos escribir en el terminal:

$ set -o ignoreeof

Así cuando pulsemos Control-D a destiempo nos dirá que para cerrar el shell escribamos exit.
Por supuesto esta línea anteriormente descrita podemos escribirla en ~/.bashrc y no tendremos que escribirla más.

Categories: Linux Tags: , , , , , ,

Ejecutar una orden externa redirigiendo STDIN [C]

Jueves, 15 de Abril de 2010 Gaspar Fernández Sin comentarios

Cuando lo hacemos desde la línea de comando, es muy fácil:

echo -e “david\njose\nalfredo\nzacarias\npatrick\ngaspar” | sort

Pero a la hora de querer hacer un programa que ejecute la orden sort, pasándole una serie de líneas no es tan intuitivo.

Para ello, he construido una tubería, y para ello hacemos que el descriptor STDIN_FILENO sea input[0] es decir, el descriptor de lectura de la pipe (con dup2).
Luego pasamos las líneas que necesitemos a la pipe a través del descriptor input[1] y lo cerramos para dar por finalizada la entrada de datos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <unistd.h>
#include <errno.h>
#include <stdio.h>

int main()
{
  int input[2];

  pipe(input);
  dup2(input[0], STDIN_FILENO);
  write(input[1], "david\njose\nalfredo\nzacarias\npatrick\ngaspar", 43);
  close(input[1]);
  execlp("sort", NULL);
  printf("ERROR : %s", strerror(errno));
}

Notas: El código fue creado rápidamente, por ello en el write, encontramos un 43 (la longitud de la cadena).

Los nombres han sido inventados, menos los dos últimos, yo soy Gaspar y Patrick es la persona a la que agradezco parte del mérito de que este fragmento de código esté hoy aquí.

Contar letras (caracteres) en EMACS

Miércoles, 14 de Abril de 2010 Gaspar Fernández Sin comentarios

letrasHay ocasiones en las que, cuando estamos escribiendo en nuestro editor de texto, necesitamos saber cuántas letras tiene un texto seleccionado.

Podemos hacerlo a la antigua usanza (la mayoría de los editores nos dicen el número de línea y carácter donde está el cursor, pues miramos al final del texto y al comienzo y restamos. Aunque emacs tiene un comando específico que nos hará esa tarea más fácil.

M-x count-lines-region

Nos devolverá el número de líneas y caracteres que tiene un texto seleccionado, como carácter se cuenta también el retorno de carro.

Por cierto, también dispone de tecla rápida: M-=

Foto: Laineys Repertoire (Flickr)

Categories: Emacs Tags: , , , ,

Visita otras webs de la red