lunes, 6 de octubre de 2008

¿Qué pasa con atoll()?


Como programador de sistemas UNIX a veces me encuentro con algunas cosas curiosas con las APIs. Hoy, sin ir mas lejos, me he vuelto loco intentando hacer funcionar atoll().

En una parte de un viejo programa, se manejaba un identificador de menos de 32 bits. Ese identificador, que provenía de una máquina Cisco en formato cadena, estaba declarado como 'int' y se transformaba mediante atoi().

Por necesidades ligadas al crecimiento de la empresa, ahora el identificador debía poder almacenar hasta 56 bits.

En pocos segundos tenía el programa funcionando con un identificador declarado como 'long', pero ooops! no funcionaba. De hecho, se comportaba como un 'int'.

El sistema, un CentOS 5.2, el compilador, gcc 4.1.2, sin problemas conocidos. Así que me dediqué a hacer algunas pruebas:

$ cat test1.c


#include<stdio.h>
int main()
{
/* 2^31 = 2147483648 */

char *str="2147483648";
long long i;

i = atoll(str);

printf("%ld\n", i);
}


$ gcc test1.c
$ ./a.out
-2147483648

Overflow, exactamente igual que un 'int'.
Me dirijo al man de atoll() y me encuentro con esto:
"The atol() and atoll() functions behave the same as atoi()"

y efectivamente. La culpa es de la función de conversión, pues con una función my_atoll() personalizada, no existe tal problema:


$ cat test2.c


#includes<stdio.h>
long long my_atoll(char *str)
{
long long res;

res = 0;
for (; *str; str++)
res = 10*res + (*str - '0');

return res;
}


int main()
{
/* 2^31 = 2147483648 */

char *str="2147483648";
long long i;

i =my_atoll(str);


printf("%lld\n", i);
}


$ gcc test2.c
$ ./a.out
2147483648


Sorprendente ...