sábado, 22 de mayo de 2010

Functors en C++

Los functors se definen como 'objetos función'.
Son la evolución natural de los punteros a función de C, un ejemplo de la sintaxis para definir un functor es el siguiente.

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

class PrinterFunctor{
private:
string msg;

public:
PrinterFunctor(string _msg){
msg = _msg;
}

void operator()(){
cout << msg << endl;
}
};


int main() {
PrinterFunctor pf("Printing from printer functor");
pf();

}

Para crear un functor simplemente hay que redefinir el operador (), tras eso podremos llamar al functor como si fuera una función más.

Con un functor podemos implementar una función 'resumible', es decir, una función que recuerde el estado anterior para producir el siguiente. Por ejemplo.

class PrimeGenerator{
private:
int currentPrime;

public:
PrimeGenerator(int _prime){
currentPrime = _prime;
}

bool isPrime(int n){
int root = (int) sqrt(n);

for(int i=2; i<root+1; i++){
if(n%i==0) return false;
}

return true;
}

int operator()(){
int n = currentPrime;

while(1){
n++;
if(isPrime(n)){
currentPrime = n;
return currentPrime;
}
}
}
};

Esta clase devolverá el siguiente número primo cada vez que la llamemos, si hacemos lo siguiente generará los 100 primeros números primos empezando por 5.

int main() {
PrimeGenerator primeGenerator(5);
for(int i=0; i<100; i++){
cout << primeGenerator() << endl;
}
}

domingo, 16 de mayo de 2010

Wingedbox


Este post es para anunciar la salida de un nuevo proyecto, wingedbox.

Es un proyecto lanzado por kikorb y por mí (javiyu). El concepto detrás de esta nueva web es compartir ficheros de una forma más ágil con tus amigos, no encontramos nada que encajara con nuestras necesidades así que decidimos hacerlo nosotros mismos.

Se le ha llamado "twitter de ficheros" de forma bastante acertada, ya que describe bastante bien la funcionalidad básica. Aún está en fase alpha pero realmente está teniendo muy buena acogida.

Pronto saldrá tanto el API público entre otras novedades, ya están disponible la visualización online de imágenes y fotos y el streaming de música.

Aún no tenemos buzón de sugerencias en la web, así que si tenéis algún tipo de duda o sugerencia podéis escribir un email tanto a kikorb como a mí.

sábado, 15 de mayo de 2010

Bloques with de python

En Java es muy común la combinación de bloques try catch finally para obtener/liberar recursos de forma segura.

En python hay otra forma más elegante de hacerlo.

class database_connection:
def __enter__(self):
print("Open database connection")
return 1
def __exit__(self, type, value, traceback):
print("Close database connection")

with database_connection() as db:
print(db)

Al definirnos una clase con los métodos __enter__ y __exit__ y ejecutarla en un bloque with se nos asegura que:

1) Al entrar al bloque se ha ejecutado el método __enter__.
2) Tanto si hay un error en el bloque with como si termina correctamente, los recursos serán liberados (llamada a la función __exit__).
3) Opcionalemente se puede devolver un valor para usarlo dentro del bloque (en este caso db), aunque no es obligatorio.

lunes, 3 de mayo de 2010

Web Storage, sessionStorage y localStorage en html 5

Con el nuevo estándar html 5 se ha introducido el concepto de web storage.

Mediante el objeto sessionStorage se puede guardar información relativa solo a la ventana actual, es decir, a diferencia de las cookies, aunque tengamos dos ventanas del navegador abiertas en una pagina del mismo dominio, la variable sessionStorage será única para cada ventana.
La sintaxis es muy sencilla, para guardar el email del usuario se puede hacer algo como lo siguiente.

sessionStorage.email='mail@sever.com'

Para recuperarlo después tan solo hay que ejecutar:

sessionStorage.email

Con el objeto localStorage se guarda información en local de forma permanente, entre ventanas del navegador, de forma global y por dominio. La sintaxis para utilizarlo es similar a la de sessionStorage.

sábado, 1 de mayo de 2010

Compilar a código ensamblador en formato intel con gcc

Aunque por defecto gcc produce código ensamblador con sintaxis AT&T al pasar la opción -S también es posible hacer que la salida sea con formato Intel.

Tan solo hay que ejecutar el siguiente comando.

gcc -S -masm=intel proc.c

Realizar las modificaciones que sean necesarias y después para hacer el enlazado.

gcc prog.s -o prog

sábado, 24 de abril de 2010

Ensamblador inline en código C

Para incluir código ensamblador en un programa escrito en C la sintaxis es la siguiente.

#include <stdio.h>

int main(){
int var1 = 1;
int var2;
int var3;

__asm__(
"inc %%eax \n\t"
"movl %%eax, %%ecx \n\t"
"inc %%ecx \n\t"
:"=a" (var2), "=c" (var3)
:"a" (var1)
);

printf("Value1: %d\n", var1);
printf("Value2: %d\n", var2);
printf("Value3: %d\n", var3);


return 0;
}

Los paréntesis se escriben dobles para escapar el carácter '%' ya que en C es un modificador de cadena.

Todas las líneas acaban en '\n\t' para que el código en ensamblador quede formateado igual que el resto.

Los registros no se usan con el nombre como tal para las entrada/salida, se usan alias del tipo "a=eax, b=ebx, c=ecx...".

En el primer apartado "=a" (var2), "=c" (var3) se les está diciendo que el contenido final de eax lo lleve a var2 y el contenido de ecx lo lleve a var3.

En el segundo apartado "a" (var1) se le dice que se comience el bloque copiando el valor de var1 a eax, actuará como entrada.

El compilador da por hecho que los registros usados para entrada/salida del bloque en ensamblador no los puede reutilizar, pero si se utilizan más registros se pueden poner en un tercer apartado de forma opcional.

El bloque ensamblador escrito antes, hará lo siguiente:

1. Copia el valor de var1 a eax.
2. Incrementa el valor de eax en 1.
3. Copia el contenido de eax a ecx.
4. Aumenta el valor de ecx en 1.
5. Copia el valor de eax a var2.
6. Copia el valor de ecx a var3.

martes, 20 de abril de 2010

Position Independent Code

El position independent code o código no dependiente de posición es aquel que se puede reubicar en memoria y aún así seguirá funcionando correctamente.

Por defecto, en Mac el código producido por gcc es PIC, pero se puede forzar a que produzca código no PIC con la opción -fno-pic.
Si tomamos por ejemplo el siguiente código en C.

#include<stdio.h>

void func(){
printf("Hello again\n");
}

int main(){
printf("Hello world\n");
func();

return 0;
}

Y lo compilamos como no PIC con la siguiente instrucción.

gcc -fno-pic -S program.c -o nopic.asm

Se obtiene.

.cstring
LC0:
.ascii "Hello again\0"
.text
.globl _func
_func:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $LC0, (%esp)
call _puts
leave
ret
.cstring
LC1:
.ascii "Hello world\0"
.text
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $LC1, (%esp)
call _puts
call _func
movl $0, %eax
leave
ret
.subsections_via_symbols

Se puede ver que la cadena almacenada en la línea 3 se referencia en la línea 10 de forma absoluta. Si cambia la ubicación del programa en memoria LC0 seguirá referenciando a la misma posición, pero allí ya no estará la cadena que se esperaba.

Por el contrario, si dejamos al compilador con las opciones por defecto, producirá código PIC, quedando de la siguiente forma.


.cstring
LC0:
.ascii "Hello again\0"
.text
.globl _func
_func:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
call L3
"L00000000001$pb":
L3:
popl %ebx
leal LC0-"L00000000001$pb"(%ebx), %eax
movl %eax, (%esp)
call L_puts$stub
addl $20, %esp
popl %ebx
leave
ret
.cstring
LC1:
.ascii "Hello world\0"
.text
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
call L6
"L00000000002$pb":
L6:
popl %ebx
leal LC1-"L00000000002$pb"(%ebx), %eax
movl %eax, (%esp)
call L_puts$stub
call _func
movl $0, %eax
addl $20, %esp
popl %ebx
leave
ret
.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
L_puts$stub:
.indirect_symbol _puts
hlt ; hlt ; hlt ; hlt ; hlt
.subsections_via_symbols

En esta ocasión se puede ver que en la línea 15 se carga la cadena, pero de forma relativa, usando la diferencia entre la posición actual y la de la cadena. Además, se puede ver que hay unas nuevas directivas al incluir la función puts.

¿Por qué puede preferirse la generación de código no PIC? Pues observando los ejemplos se puede ver que generar código no dependiente de la posición del programa requiere más instrucciones en ensamblador y por tanto mayor tiempo a la hora de ejecutarse.