Archivo

Archivo para Diciembre, 2010

DWGO - Nueva versión con bugs corregidos

Miércoles, 22 de Diciembre de 2010 Gaspar Fernández Sin comentarios

Dwgo es un programa que hice hace un par de años para mostrar la temperatura en varios lugares. Concretamente es una dockapp (sé que están algo anticuados ya) compatible con WindowMaker, Fluxbox, Openbox, Blackbox y algunos gestores de ventanas más. Aunque con proyectos como xdock podemos utilizar este tipo de programas en cualquier otro gestor que no sea compatible (como KDE, Gnome y estos más grandes).

dwgoSe trata de una versión de corrección de bugs : como un problema con MySock y con la gestión de errores; así como un problema a compilar en algunos sistemas. Esta versión es mucho más estable, y sigue consumiendo una cantidad de memoria muy baja por lo que podemos ejecutarlo y tenerlo cargado sin problemas.

El programa soporta temas para representar el tiempo que hace en diferentes lugares tanto para lluvia, sol, nublado, niebla, etc; estos temas se pueden personalizar desde el fichero de configuración del programa. Además, para cambiar de estación (y por tanto ver el tiempo de otra ciudad, sólo tenemos que hacer click en el dockapp).

El código fuente, así como los fuentes de las imágenes, se pueden descargar desde aquí :  dwgo-0.4.tar.gz.

Para más información podéis visitar la página web (por ahora en inglés): Dwgo quiero subir información nueva los próximos días.

El software está programado en C++ y liberado bajo GPL v3.

89 segundos. El tiempo medio de arranque de un ordenador…

Miércoles, 22 de Diciembre de 2010 Gaspar Fernández 4 comentarios

Hace poco en la revista Muy interesante leí un dato curioso. La media de tiempo de arranque de un ordenador es de 89 segundos, y eso hace que si lo arrancamos todos los días, perdamos algo más de 9h al año en arranques de ordenador.

Lo curioso es que a mi me parece algo excesivo, ¡89 segundos! Siempre depende del hardware que se tenga y de los servicios que se arranquen, bueno, y del sistema operativo que corra. Me gustaría hacer en los próximos días una pequeña encuesta vía Twitter/Facebook/Blog acerca de los tiempos de arranque de sus ordenadores.

A ver lo que sale… ¿ cuánto tarda tu ordenador en iniciarse ? Dejadlo en comentarios, me gustaría que escribierais el tiempo, el hardware (no muy exhaustivo tampoco CPU y RAM) o el tiempo que tiene el ordenador y el sistema operativo.

Actualizado MySock para C++

Sábado, 18 de Diciembre de 2010 Gaspar Fernández Sin comentarios

Hace mucho tiempo publiqué MySock, una clase para acceder a sockets y sobre todo para extraer datos a webs de forma rápida. No es un reemplazo de cURL, ya que no tiene muchas características, pero para algo rápido está bien porque es muy pequeño y no tiene dependencias.

Ahora traigo una revisión del código de MySock con algunos errores corregidos:

  • En ocasiones no se encontraban webs que en realidad sí existían
  • El socket teníamos que cerrarlo a mano… (la culpa la tiene un proyecto que hice que luego aprovechaba el socket para otras cosas…)
  • Hay un método para cerrar el socket a mano. closeConnection()

El archivo se puede descargar aquí:mysock.tar.gz (3.7Kb)

Categories: General Tags: , , , ,

El método más rápido para traer un valor pasado por $_GET [ PHP ]

Miércoles, 15 de Diciembre de 2010 Gaspar Fernández 1 comentario

Tal vez por paranoia, por ganas de perder el tiempo, o por optimizar aún más el código fuente nos encontremos ante esta cuestión.

He realizado una serie de pruebas para ver cuál es el método que mejor funciona para traer un valor de $_GET basándome en el peor de los casos: cuando este valor no existe. Tal vez las pruebas no tengan excesiva validez por el método utilizado, aunque he intentado hacer todas las pruebas en las mismas condiciones.

Las medidas de tiempo han sido tomadas con el comando time de la siguiente manera:

$ time php myscript.php

Se han hecho un total de 7 pruebas, 1 de ellas de control. Las pruebas se han basado en la generación de cadenas aleatorias (que más tarde serán nuestro parámetro $_GET), además, la obtención del parámetro ha sido hecha unas 500000 veces con un bucle for. Se detallan las pruebas realizadas.
Cada prueba se ha repetido tres veces y se ha capturado el tiempo de las tres veces. Estamos usando un software complicado que hará muchas cosas mientras se realiza el test, es más, el sistema operativo puede requerir hacer una tarea que puede influir en nuestro resultado, por lo que así minimizamos el error (y si en alguna ocasión sale un dato desorbitado podemos descartarlo).

Prueba de control [TEST 0]

La generación de parámetros es lo que más tarda. Se ha utilizado uniqid() para obtener cadenas de la misma longitud y contenido arbitrario y diferente cada vez. Además, tanto la obtención del parámetro (en las siguientes pruebas) como la generación del nombre del parámetro se hace un número N de veces gracias a un bucle (que también invierte un tiempo).

Con esta prueba de control podremos ver en qué grado son significativos los valores obtenidos luego (cuando hagamos la obtención de datos), ya que vemos que el bucle y la generación tardan de media 4.493 segundos.

El código fuente del script para esta prueba es el siguiente:

1
2
3
4
5
echo "Probando 500000 peticiones GET";
for ($i=0; $i<500000; $i++)
{
$getVar=uniqid();
}

Anulando error_reporting() [TEST 1]

Lo que nos impide hacer un $variable=$_GET['parametro']; es el error_reporting, ya que si éste no existe, nos devolverá un feo error por pantalla. Así que probemos primero desactivando esto y obteniendo el valor de la variable.

1
2
3
4
5
6
7
echo "Probando 500000 peticiones GET";
error_reporting(E_NONE);
for ($i=0; $i<500000; $i++)
{
$getVar=uniqid();
$dato=$_GET[$getVar];
}

Con @$_GET[...] [TEST 2]

Otra manera de impedir que PHP muestre sus errores en pantalla, es colocando una @ delante de lo que creemos que puede fallar, y en este caso es la sentencia de $_GET[$getVar].

1
2
3
4
5
6
7
echo "Probando 500000 peticiones GET";

for ($i=0; $i<500000; $i++)
{
$getVar=uniqid();
$dato=@$_GET[$getVar];
}

if…else [TEST 3]

No es nada intuitivo, PHP es un lenguaje de scripting, así que cuanto más escribamos, peor, pero merece la pena hacer la prueba, y nos podemos llevar una sorpresa. Ahora, hacemos la obtención del dato, pero primero comprobamos que éste existe con isset().

1
2
3
4
5
6
7
8
9
echo "Probando 500000 peticiones GET";
for ($i=0; $i<500000; $i++)
{
$getVar=uniqid();
if (isset($_GET[$getVar]))
$dato=@$_GET[$getVar];
else
$dato=false;
}

Operador ternario ? [ TEST 4 ]

Tal vez vaya mejor que el if…else (TEST 3), por aquella razón de escribir menos que comentaba…

1
2
3
4
5
6
echo "Probando 500000 peticiones GET";
for ($i=0; $i<500000; $i++)
{
$getVar=uniqid();
$dato=(isset($_GET[$getVar]))?$_GET[$getVar]:false;
}

Creando una función auxiliar gval() [ TEST 5 ]

Tal vez escribimos más que con el TEST 2 pero, vamos a probar, qué tal va. Tal vez si la diferencia de tiempo no es significativa podemos utilizar este método…

1
2
3
4
5
6
7
8
9
10
11
function gval($getVar)
{
return (isset($_GET[$getVar]))?$_GET[$getVar]:false;
}

echo "Probando 500000 peticiones GET";
for ($i=0; $i<500000; $i++)
{
$getVar=uniqid();
$dato=gval($getVar);
}

Función auxiliar y parámetro por referencia [ TEST 6 ]

Una nueva prueba, ya que hemos hecho una función auxiliar, veamos cómo influye el pasar el parámetro por valor o pasarlo por referencia. En este caso podríamos hacerlo sin problema.

1
2
3
4
5
6
7
8
9
10
11
function gval(&amp;$getVar)
{
return (isset($_GET[$getVar]))?$_GET[$getVar]:false;
}

echo "Probando 500000 peticiones GET";
for ($i=0; $i<500000; $i++)
{
$getVar=uniqid();
$dato=gval($getVar);
}

Resultados obtenidos

Tipo de prueba Primer resultado Segundo resultado Tercer Resultado Media
TEST 0 4,4530 4,5960 4,4310 4,4933
TEST 1 6,7560 6,1390 5,8350 6,2433
TEST 2 7,3880 7,3350 7,3120 7,3450
TEST 3 5,5270 4,9900 5,0610 5,1927
TEST 4 5,4480 4,9820 5,1060 5,1787
TEST 5 6,2860 6,4050 5,8160 6,1690
TEST 6 5,9840 5,6290 5,7440 5,7857

Con estos resultados podemos observar que:

  • Efectivamente, el test de control es el más lento, incluye generación del nombre aleatorio del parámetro, el bucle y la carga del programa (PHP), pero más o menos partimos de que el tiempo mínimo para esta prueba son cerca de 4.5 segundos. El tiempo de obtención de dato, será más o menos la diferencia entre el tiempo total del test y los 4.5 segundos aproximadamente obtenidos aquí.
  • TEST 1: error_reporting(E_NONE) nos entorpecería en tareas de depuración (cuando realmente deseemos tenerlo en otro valor), de todas formas no es una opción, comparado con los demás. Deberíamos estar pendientes del valor de error_reporting() cuando queramos depurar el script, no ahorraríamos mucho código y tampoco es el mejor con respecto al tiempo.
  • TEST 2: Estaría bien que un carácter nos solucionara la vida, pero no es así… conseguimos el peor tiempo de todos. Se ve que a PHP le sienta mal cuando no encuentra una variable…
  • TEST 3 y TEST 4: Parece que un if…else nos puede ayudar a hacer nuestro código más rápido, un poco más elegante y funcionar mejor. También vemos que el operador ? puede ayudar. Y vemos, además, que el tiempo entre if…else y entre ? es el mismo (la diferencia es despreciable en este caso)
  • TEST5: Visto lo visto con TEST3 y TEST4 en los que escribimos más que con TEST2, vamos a crear una función auxiliar, a ver cómo se comporta con respecto a lo que tenemos. Comprobamos que el uso de una función, hace nuestro código más claro (punto positivo) y aún tarda menos que TEST1 y TEST2 aunque tarda algo más que TEST3 y TEST4. TEST5 tarda aproximadamente lo que TEST1.
  • TEST6: Parece que el hecho de no copiar el valor de una variable de verdad influye significativamente en el tiempo cerca de medio segundo; podemos seguir utilizando un método elegante con nuestra función auxiliar y al mismo tiempo aproximarnos a un tiempo mínimo.
  • Sé que 500000 iteraciones puede parecer exagerado aunque en momentos de carga de servidor y cuando esperamos que nuestra página tenga un número importante de visitas tal vez se agradezca un poco de agilidad, sobre todo en recepción de formularios (con variables $_POST). De todas formas, queda claro con estas pruebas que el hecho de poner una @ en un comando o asignación, sólo hace que PHP se trague los errores, pero es un método lento, con lo que podemos empezar a optimizar nuestro código por ahí.

Un apaño para el efecto de kscreenlocker en algunas tarjetas gráficas

Martes, 14 de Diciembre de 2010 Gaspar Fernández 2 comentarios

ksolarwinds_colgado

Si, como yo, tienes una tarjeta Intel, algunas actualizaciones de KDE y Xorg te pueden dejar con mal sabor de boca, ya que cuando salte el protector de pantalla, si tenemos activada la opción de que nos pregunte contraseña, te va a dejar así la pantalla.

Si escribimos la contraseña tal cual, no pasa nada, es decir, volveremos a entrar, aunque es molesto que no se vea nada, y si queremos sorprender a las visitas, con esto, sí que no lo vamos a conseguir.

Es un bug, espero que en las últimas versiones esté corregido, aunque en versiones estables seguimos viendo este fallo. La solución, o bueno, chapucilla o apaño, workaround, como dirían en tierras anglosajonas es el siguiente: ejecutar kscreenlocker (es decir el programa que bloquea la sesión con la siguiente variable de entorno: XLIB_SKIP_ARGB_VISUALS=1; lo malo es que no podemos arrancar KDE con esta configuración ya que debido a la composición de ventanas no arrancaría; además, se debe quedar muy soso sin composición, sin efectos y sin nada, y no queremos eso.

Tenemos que arrancar sólo kscreenlocker con esa configuración, y podemos hacer lo siguiente (como root):

  1. Buscamos el ejecutable kscreenlocker (con locate, por ejemplo). En Linux Mint lo podemos encontrar en: /usr/lib/kde4/libexec/kscreenlocker.
  2. Lo renombramos como kscreenlocker_ (o con cualquier otro nombre)
  3. Luego creamos un archivo llamado kscreenlocker (un script donde añadimos la variable que queremos) y contendrá lo siguiente:

    export XLIB_SKIP_ARGB_VISUALS=1
    /usr/lib/kde4/libexec/kscreenlocker_ $@

  4. Damos permisos de ejecución:

    chmod +x kscreenlocker

No deja de ser un arreglo provisional, ya que cuando actualicemos algún componente, seguramente se romperá esto, pero al menos no nos deja ese desagradable sabor de boca.

Las teclas que utilizo más frecuentemente en Emacs / Guía para principiantes

Sábado, 11 de Diciembre de 2010 Gaspar Fernández 3 comentarios

Hace unos días hablé de la importancia de conocer los atajos de teclado de tu IDE favorito; hoy hablaré de las teclas que más utilizo en el mío, Emacs, y de paso hago una pequeña guía para principiantes en este editor.

I. Un apunte básico del uso del teclado en Emacs

Lo primero que hay que mencionar es que hay muchas combinaciones con la tecla Control y Alt (o Meta), cuando una tecla, por ejemplo, la “x” se pulsa junto con Control diremos C-x y cuando esa misma tecla la pulsamos junto con Alt diremos M-x cuando pulsamos una combinación por ejemplo (M-g) y luego tenemos que soltar las teclas y pulsar una tecla sola, por ejemplo, otra g, diremos (M-g g), lo mismo vale con combinaciones, si tenemos que pulsar primero C-x y luego C-c diremos: “C-x C-c”

Si por alguna casualidad no podemos pulsar la tecla Meta, o una combinación (como sucede en algunos tipos de terminales remotos), podemos, para pulsar M-x, pulsar “Escape x”

II. Acceder al comando que queremos ejecutar

Una de las muchas cosas buenas que tiene Emacs es que todo lo que podemos hacer por teclado tiene un comando asociado, incluso para muchas acciones que no tienen tecla asociada. Por otra parte, también tenemos que decir que las teclas se pueden personalizar, por lo que estas teclas que diré (si no digo lo contrario) son las que vienen por defecto, y que casi todos los usuarios mantenemos porque suelen ser cómodas de pulsar, aunque en algunas ocasiones serían cómodas en un teclado inglés… pero te terminas acostumbrando.

Como iba diciendo, para ejecutar un comando debemos pulsar M-x y podremos, desde el minibuffer escribir el comando que queremos ejecutar, eso sí, disponemos de completion por lo que en cualquier momento podemos pulsar tab y veremos las posibilidades que tenemos. Incluso podemos pulsar M-x tab y veremos todas las posibilidades que tenemos, hay que recordar que podemos cargar extensiones y éstas pueden añadir comandos nuevos. Es más, la lista de comandos se abrirá en un nuevo buffer de Emacs, con lo que podremos buscar en ese buffer (no siempre nos acordamos de cómo empieza un comando). Para buscar también podemos hacer M-h a.

III. Me he equivocado con tanta combinación de teclas. ¿ Qué hago ?

Pulsar C-g en cualquier momento, eliminará todo lo que hemos pulsado hasta ahora. Es cierto, que a veces hay combinaciones demasiado largas, o en ocasiones hemos empezado a pulsar algo y nos arrepentimos, bien C-g es la solución para seguir por donde estábamos.

También podemos pulsar C-g si queremos cancelar una acción en curso, como por ejemplo salir, cuando tenemos muchos buffers abiertos y nos pregunta si queremos guardar o no, podemos pulsar C-g para que deje de preguntar por archivos y no salir del programa.

IV. Comandos básicos de un editor de texto

  • Abrir archivo: C-x C-f nos preguntará qué archivo abrir, podemos navegar por directorios desde el minibuffer, tenemos además la posibilidad de completar el nombre del archivo. (A lo bash)
  • Nuevo archivo: C-x C-f ¡ igual que antes ! y es que no hacemos nada diferente, abrimos un nuevo buffer. El archivo no se creará hasta que no lo salvemos por primera vez, así que, sin problema.
  • Salvar archivo: C-x C-s Salvamos el archivo con el nombre que tiene.
  • Salvar como: C-x C-w Nos pregunta con qué nombre nuevo queremos salvar el archivo
  • Salir: C-x C-c Salimos, nos preguntará
  • Buscar un texto: C-s (busca hacia adelante) C-r (busca hacia atrás) La primera vez que pulsamos cualquiera de las teclas, nos preguntará qué texto buscar, luego podemos jugar y buscar adelante y atrás como queramos.
  • Deshacer: Es posíblemente la opción peor implementada en Emacs, pero a veces hace el apaño. Podemos pulsar C-x u para deshacer un carácter o C-u C-x u para deshacer un conjunto de caracteres.
  • Seleccionar texto: Podemos hacerlo con el ratón o pulsar C-espacio, soltar y movermos con las teclas (flechas, re-pag, av-pag, inicio, fin y combinaciones.
  • Copiar: Con un texto seleccionado, pulsamos M-w
  • Cortar: Con un texto seleccionado, pulsamos C-w
  • Pegar: Pulsar C-y, pero si queremos pegar alguno de los textos copiados antes del último, justo después de C-y pulsamos M-y, e iremos navegando por todo lo que hemos ido copiando anteriormente.
  • Cambiar de ventana: C-b y seguidamente escribimos el nombre del fichero que queremos editar (de los que previamente están abiertos. O también C-x C-b para ver un listado de ficheros abiertos.
  • Cerrar buffer: C-x k Cerramos el buffer abierto ahora mismo, si correspondía con un fichero y no hay más buffers con ese fichero abierto, cerraremos el fichero y si tiene algún cambio, nos preguntará si queremos salvarlo.

V. Comandos para movernos más rápidamente

Algunos de estos son utilizados en más lugares:

  • C-k Elimina desde la posición actual del cursor hasta fin de línea. Estamos cortando el texto, por lo que la línea se copiará automáticamente.
  • M-< Saltamos al principio del buffer
  • M-> Saltamos al final del buffer
  • C-arriba / C-abajo : Nos moveremos verticalmente en bloques, es decir entre líneas en blanco o entre funciones, entre comentarios, etc
  • C-l Centra el buffer actual en la posición del cursor. Si se nos ha perdido el cursor es muy útil, o si estamos leyendo un documento.
  • M-g g nos preguntará a qué línea nos queremos ir del texto.
  • C-x h Selecciona el buffer completo
  • M-h Selecciona el párrafo actual

VI. Visualizando varios buffers a la vez

Emacs nos permite, en la misma ventana (aunque aquí se llame frame) tener varios cuadros de texto (que Emacs llama windows):

  • C-x 2 dividimos horizontalmente la pantalla, para tener un buffer arriba y otro abajo
  • C-x 3 dividimos verticalmente la pantalla, así tenemos un buffer a la derecha y otro a la izquierda.
  • C-x 0 (cero) eliminamos el buffer seleccionado
  • C-x o (letra O) cambiamos de buffer, nos vamos al de al lado, aunque también podemos seleccionarlos con ratón

VII. A la hora de programar nos será muy útil…

  • C-; Si tenemos un texto seleccionado, comentará ese texto, si no introducirá un comentario al final de la línea.
  • C-M-@ Si tenemos un texto seleccionado, se auto-indentará todo dependiendo del lenguaje de programación que estemos escribiendo.
  • M-/ Se completará automáticamente la palabra que estamos escribiendo ahora mismo.
  • Cuando hacemos C-espacio, C-s, C-r, etc vamos a irnos a otra posición diferente a la que estábamos, por lo que necesitamos una tecla para regresar: C-x C-x ; es útil cuando programamos y tenemos que escribir algo arriba del todo, y luego regresar a la línea donde seguimos escribiendo.
  • C-x r espacio Nos hará una pregunta, pulsamos una letra cualquiera, por ejemplo a. Guardará la posición en esa a
  • M-x register-to-point Nos preguntará una posición, por ejemplo, la de antes: a; y nos lanzará a esa parte del texto. (Podremos vincularlo a una tecla si lo usamos bastante.

Aunque parece que tenemos que estudiar para utilizar el editor, basta con una semana para habituarse a las teclas básicas, y poco a poco, llamando a los comandos M-x  indent-region (por ejemplo) nos dirá la tecla que debemos pulsar para acceder rápidamente.

Restablecer contraseña de root en servidor MySQL

Miércoles, 8 de Diciembre de 2010 Gaspar Fernández Sin comentarios

En ocasiones, sobre todo en nuestro servidor de pruebas (que a lo mejor puede ser
nuestro servidor de producción), podemos perder la contraseña de root de MySQL, y es un
fastidio, porque se nos puede pasar por la cabeza reconfigurar el paquete y perderlo
todo, pero son momentos en los que hay que tener paciencia y si tenemos información, no
es plan de destruir gratuitamente los datos.

Para ello, dejo unos sencillos pasos con los que restableceremos la contraseña de root
de MySQL (es necesario tener privilegios en el ordenador en el que está instalado
MySQL):

1. Primero detenemos el servicio MySQL, aquí dejo tres formas dependiendo de la
distribución:

1.1. $ service mysqld stop
1.2. $ /etc/init.d/mysqld stop
1.3. $ /etc/rc.d/mysqld stop

2. Tras ello, con privilegios de root, arrancamos MySQL de un modo especial, ignorando
las tablas de privilegios.

root $ mysqld –skip-grant-tables

Dependiendo de la versión de MySQL, puede que no nos deje arrancar el demonio como
usuario root, por lo que le daremos un nombre de usuario (este será el usuario con el
que arrancará mysql)

root $ mysqld -u mysql –skip-grant-tables &

En la mayoría de los sistemas el usuario será mysql.

3. Accedemos al servicio como superusuario (ya que no se comprueban las tablas de
privilegios, tenemos acceso). Esto lo podemos hacer como usuario normal. Accederemos
también a la base de datos llamada mysql (donde estan las tablas de privilegios)

$ mysql -u root mysql &

4. Desde mysql establecemos la nueva contraseña:

mysql> UPDATE mysql.user SET Password=PASSWORD(’nueva_contraseña’) WHERE
User=’root’;
mysql> FLUSH PRIVILEGES;

5. Salimos

mysql> quit

6. Cerramos mysqld (como root), tardará unos segundos, debemos ser pacientes

$ killall mysqld

7. Iniciamos el servidor MySQL normalmente, del mismo modo que lo paramos en el paso 1:

7.1. $ service mysqld start
7.2. $ /etc/init.d/mysqld start
7.3. $ /etc/rc.d/mysqld start

Ya debemos poder trabajar normalmente con nuestra nueva contraseña.

Cronometrando en C

Domingo, 5 de Diciembre de 2010 Gaspar Fernández 4 comentarios

Puede que queramos hacer una comparativa de cuánto tarda nuestro código en ejecutarse, o que tengamos varios algoritmos y queramos saber cuál es el más rápido. O que estemos haciendo un programa que mida el tiempo de reacción de un usuario en una cierta tarea. Aquí vemos ejemplos con diferentes precisiones.

Minutos

Este método viene bien para ver el tiempo transcurrido en un proceso que puede durar varios minutos. Si algo tarda 20 minutos, suele darnos igual segundo arriba, segundo abajo.

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

int main(int argc, char *argv[])
{
int anterior;
anterior=time(NULL);
sleep(1);
printf("Transcurrido: %ld\n", time(NULL)-anterior);
}

Sí, simplemente es esto, pero no voy a hacer un post sólo para esto, vamos a crear una función que llamemos cuando queremos empezar a cronometrar y volvamos a llamar cuando queramos parar:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <time.h>

int cronosec(int startstop)
{
  static int pre_time;

  if (startstop)
    pre_time=time(NULL);
  else
    return time(NULL)-pre_time;

  return 0;
}

int main(int argc, char *argv[])
{
  cronosec(0);
  sleep(1);
  printf("Transcurrido: %ld\n", cronosec(1));
}

Con cronosec cuando empezamos a cronometrar, pasamos el parámetro 0, y cuando queremos ver el tiempo transcurrido llamamos al parámetro 1.

Precisión de milisegundo y microsegundo

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
32
33
34
35
36
37
38
#include <unistd.h>
#include <sys/time.h>

long long cronomsec(int startstop)
{
  static long long pre_time;
  struct timeval tv;

  if (startstop)
    {
      gettimeofday(&tv, NULL);      
      pre_time=tv.tv_sec*1000+tv.tv_usec/1000;
    }
  else
    {      
      gettimeofday(&tv, NULL);      
      return tv.tv_sec*1000+tv.tv_usec/1000 - pre_time;
    }
    return 0;
}

long long cronousec(int startstop)
{
  static long long pre_time;
  struct timeval tv;

  if (startstop)
    {
      gettimeofday(&tv, NULL);      
      pre_time=tv.tv_sec*1000000+tv.tv_usec;
    }
  else
    {      
      gettimeofday(&tv, NULL);      
      return tv.tv_sec*1000000+tv.tv_usec - pre_time;
    }
    return 0;
}

Las dos se usan igual que cronosec(), cronomsec() tiene precisión de milisegundos y cronousec() de microsegundos; si las observamos las dos son iguales, sólo que en una, como queremos contar milisegundos, multiplicamos los segundos por mil y dividimos microsegundos entre 1000 (struct timeval es capaz de devolvernos microsegundos también).
En cronousec sólo multiplicamos los segundos por 1000000 (un millón).

Nanosegundo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <time.h>

unsigned long long crononsec(int startstop)
{
  static unsigned long pre_time;
  static unsigned long pre_secs;
  struct timespec ts;

  if (startstop)
    {
      clock_gettime(CLOCK_MONOTONIC, &ts);
      pre_time=ts.tv_nsec;
      pre_secs=ts.tv_sec;
    }
  else
    {      
      clock_gettime(CLOCK_MONOTONIC, &ts);
      return (ts.tv_sec-pre_secs)*1000000000+ts.tv_nsec - pre_time;
    }

    return 0;
}

Con esta función, gracias a clock_gettime(), obtenemos precisión de nanosegundos. Utilizo CLOCK_MONOTONIC porque este reloj no cambia, es decir, existe la función clock_settime, y este reloj no se podrá cambiar, de hecho no queremos que nos hagan trampa en nuestras aplicaciones, cambien la hora del ordenador y nuestro programa no funcione bien. Si no, podemos usar CLOCK_REALTIME, aunque este se puede cambiar, aunque necesita privilegios.
En este último ejemplo, vemos que no multiplico los segundos desde el principio como hacía antes, ahora sólo acumulo segundos, y luego multiplico la diferencia; esto es, porque el número de segundos ya acontecidos desde 1970 (Epoch) es demasiado grande, y si lo multiplico por 1000000000 (mil millones) para saber cuántos microsegundos han pasado desde entonces, el número es demasiado grande y desborda la variable (mira que es long long y tiene 64bits), así que aplico este método, mucho más inteligente y menos costoso (dos multiplicaciones frente a una), también podía hacer todos los métodos anteriores así, aunque el precio de hacer menos operaciones es la reserva de una variable más.

Un ejemplo para probarlo todo

Una vez colocadas todas las funciones en un archivo .c y todos los includes correspondientes arriba, añadimos este main():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main(int argc, char *argv[])
{
  cronosec(1);
  cronomsec(1);
  cronousec(1);
  crononsec(1);
  usleep(4123789);      /* 4 segundos y pico*/
  printf("segundos: %d\n", cronosec(0));
  printf("milisegundos: %lld\n", cronomsec(0));
  printf("microsegundos: %lld\n", cronousec(0));
  printf("nanosegundos: %llu\n", crononsec(0));
 
  return EXIT_SUCCESS;
}

Una advertencia, las funciones que tienen más precisión de segundos son dependientes de la plataforma, además, para compilarlos necesitamos añadir la librería rt al compilar, de la siguiente forma:

$ gcc -lrt -o crono crono.c

Separar palabras de una cadena de caracteres en un array [ C ]

Jueves, 2 de Diciembre de 2010 Gaspar Fernández Sin comentarios

Si conocéis PHP, habréis visto la función explode(). Tiene una utilidad curiosa, separa cadenas de caracteres en elementos de un array. Es como hacer un corte a la cadena cada vez que encontremos un carácter delimitador. Por ejemplo:

“Bienvenido al blog Poesía Binaria”, si usamos como delimitador ” ” (un espacio), los elementos del array quedarían así:

[0] = “Bienvenido”
[1] = “al”
[2] =”blog”
[3] =”Poesía”
[4] = “Binaria”

Pero en C, no encontramos ninguna función que haga esto, tenemos que currar un poco; aunque tenemos una función de string.h que hace algo que se parece en cierto modo: strtok(), esta función, va a separar una cadena en fragmentos modificando la propia cadena, es decir, introduciremos caracteres terminadores al final de cada palabra.

La solución intuitiva, sería hacer una copia en una variable de la original, y utilizar la copia para strtok() aunque el acceso a cada palabra no es tan flexible, es decir, strtok() nos devolverá un puntero a donde empieza la palabra, pero en cuanto queramos conocer la siguiente palabra que encontremos no podremos volver fácilmente a la anterior.

Por ello, planteo la siguiente solución:

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
32
33
34
35
36
37
38
39
40
41
42
#define MAX_CADENA 100

/**
 ******************************************************************
 * @brief Extrae palabras de una cadena y las coloca en un array
 *
 * @param orig     Cadena inicial
 * @param delim    Las palabras vendrán delimitadas por uno de los
 *                 caracteres de esta cadena            
 * @param args     Array donde separaremos cada palabra
 * @param max_args Número de palabras como máximo a extraer (tamaño
 *                 del array)
 *
 * @return Número de palabras extraídas. (max_args+1) si en la
 *         cadena hay más de max_args palabras.
 *
 ******************************************************************/

int extrae_argumentos(char *orig, char *delim, char args[][MAX_CADENA], int max_args)
{
  char *tmp;
  int num=0;
  /* Reservamos memoria para copiar la candena ... pero la memoria justa */
  char *str = malloc(strlen(orig)+1);
  strcpy(str, orig);

  /* Extraemos la primera palabra */
  tmp=strtok(str, delim);
  do
    {
      if (num==max_args)
    return max_args+1;  /* Si hemos extraído más cadenas que palabras devolvemos */
                /* El número de palabras máximo y salimos */

      strcpy(args[num], tmp);   /* Copiamos la palabra actual en el array */
      num++;

      /* Extraemos la siguiente palabra */
      tmp=strtok(NULL, delim);
    } while (tmp!=NULL);

  return num;
}

Con esta función ejecutaremos strtok para extraer palabras de una cadena, como máximo (max_args+1) veces. El objetivo es rellenar el Array, debido a las limitaciones de los Arrays tenemos que decir el número máximo de elementos que vamos a extraer, la cadena podrá tener 1000 palabras, pero si nuestro array sólo tiene capacidad para 10 no podremos extraer todo; y la función debe estar preparada para eso; por tanto cuando no hayamos podido extraer todo, devolveremos max_args+1, si todo va bien, devolveremos el número de palabras extraídas.

Lo curioso es que cambiando sólo una línea podemos hacer que admita en lugar de un array de cadenas de caracteres (char args[][MAX_CADENA]) un array de punteros de cadenas de caracteres (char *args[]) por lo que en cierto modo, depende del uso que vayamos a darle es algo más flexible, en este caso repartiremos en el array anterior los valores de las posiciones de memoria donde empieza cada palabra en la cadena copiada de la original:

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
int extrae_argumentos_d(char *orig, char *delim, char *args[], int max_args)
{
  char *tmp;
  int num=0;
  /* Reservamos memoria para copiar la candena ... pero la memoria justa */
  char *str = malloc(strlen(orig)+1);
  strcpy(str, orig);

  /* Extraemos la primera palabra */
  tmp=strtok(str, delim);
  do
    {
      if (num==max_args)
    return max_args+1;  /* Si hemos extraído más cadenas que palabras devolvemos */
                /* El número de palabras máximo y salimos */

      args[num]=tmp;            /* Copiamos la dirección de memoria tmp en args[num] */
      num++;

      /* Extraemos la siguiente palabra */
      tmp=strtok(NULL, delim);
    } while (tmp!=NULL);

  return num;
}

Ahora acompaño un programa para probar esto:

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
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MAX_ARGS 90
#define MAX_CADENA 100

// Aquí copiamos extrae_argumentos o extrae_argumentos_d
int main()
{
  char cadena[]="Una ristra de palabras separadas por espacios";

  char args[MAX_ARGS][MAX_CADENA]; // Para extrae_argumentos
//  char *args2[MAX_ARGS];                  // Para extrae_argumentos_d

  int nargs = extrae_argumentos(cadena, " ", args, MAX_ARGS);
  int i;

  if (nargs>MAX_ARGS)
    {
      printf ("Se han devuelto más palabras del máximo\n");
      nargs=MAX_ARGS;
    }

  printf("CADENA: %s\n", cadena);
  for (i=0; i<nargs; i++)
    printf("Palabra %d: \"%s\"\n", i, args[i]);

  return 0;
}

Nuevo en Ranking Linux. Intentando hacer encontrable esta web

Miércoles, 1 de Diciembre de 2010 Gaspar Fernández 3 comentarios

Hace unos días que me di de alta en Ranking Linux aunque es ahora mismo cuando he publicado el enlace en la web. Además de en este ranking he añadido algún que otro directorio web más a la lista.

Por otra parte, decir que si tienes un blog de programación, o relacionado con el software libre y quieres hacer un intercambio de enlaces, estaré encantado; puedes enviarme un comentario o un mensaje privado.

Categories: General Tags:

Visita otras webs de la red