2010-11-09 15 views
6

me trataroncómo convertir una cadena hexadecimal a un entero sin signo de 64 bits (uint64_t) de una manera rápida y segura?

sscanf(str, "%016llX", &int64); 

pero no parece segura. ¿Hay una manera rápida y segura de hacer el tipo de casting?

Gracias ~

+0

¿Qué quiere decir con "no seguro"? –

+1

No lo sé. Traté de usar esto para hacer el casting entre un gran número de cadenas hexagonales, y algunas veces reportaba la falla del segmento –

+0

¿Podría mostrar la declaración y la inicialización de 'str'? – Flinsch

Respuesta

7

No se moleste con las funciones de la familia scanf. Son casi imposibles de usar de forma robusta. He aquí un uso seguro general de strtoull:

char *str, *end; 
unsigned long long result; 
errno = 0; 
result = strtoull(str, &end, 16); 
if (result == 0 && end == str) { 
    /* str was not a number */ 
} else if (result == ULLONG_MAX && errno) { 
    /* the value of str does not fit in unsigned long long */ 
} else if (*end) { 
    /* str began with a number but has junk left over at the end */ 
} 

Tenga en cuenta que la admisión de una strtoull0x prefijo opcional de la cadena, así como espacio en blanco inicial opcional y un carácter de signo (+ o -). Si desea rechazar éstos, se debe realizar una prueba antes de llamar strtoull, por ejemplo:

if (!isxdigit(str[0]) || (str[1] && !isxdigit(str[1]))) 

Si también desea no permitir excesivamente largas representaciones de números (ceros a la izquierda), se puede consultar la siguiente condición antes de llamar strtoull:

if (str[0]=='0' && str[1]) 

Una cosa más a tener en cuenta es que "los números negativos" no se consideran fuera del rango de conversión; en su lugar, un prefijo de - se trata de la misma manera que el operador de negación unaria en C aplicado a un valor sin signo, de modo que por ejemplo strtoull("-2", 0, 16) devolverá ULLONG_MAX-1 (sin establecer errno).

+0

En general, estoy de acuerdo con sus opiniones con respecto a la familia 'scanf()'. * Tienen sentido * en entornos controlados, p. leyendo en archivos que su aplicación ha escrito en sí misma – DevSolar

+0

@DevSolar: De hecho, mi comentario fue pensado como una respuesta a la pregunta de OP sobre el uso seguro, no consejos generales. La familia 'scanf' funciona bien para leer archivos'/proc' de Linux, por ejemplo. –

+0

¿No 'strtoull() 'devolvería un tipo' unsigned long long ', que no es necesariamente un tipo' uint64_t '? – GreySage

2

Su título (en la actualidad) contradice el código que ya ha proporcionado. Si quieres hacer lo que originalmente era tu título (convertir una cadena en un entero), entonces puedes usar esta respuesta.


Se puede usar la función strtoull, que a diferencia de sscanf es una función específicamente dirigido a la lectura de las representaciones textuales de números.

const char *test = "123456789abcdef0"; 

errno = 0; 
unsigned long long result = strtoull(test, NULL, 16); 

if (errno == EINVAL) 
{ 
    // not a valid number 
} 
else if (errno == ERANGE) 
{ 
    // does not fit in an unsigned long long 
} 
+1

Según entiendo, él quiere convertir de un número entero a una cadena, no viceversa. ;) – Flinsch

+1

@Flinsch, el título cambió, pero su código original sugiere que quiere convertir de cadena a entero. No estoy seguro de que pueda ver el historial de edición de la pregunta, pero el título originalmente decía que quería convertir una cadena en un número entero. – dreamlax

+0

En realidad, 'scanf()' et al. están * definidos * en términos de 'strtol()'. Para una entrada medianamente decente, son funcionalmente idénticos en cuanto a números de análisis. Admito que 'strtol()' maneja la falla más elegantemente. – DevSolar

0

En el momento de escribir esta respuesta, el título sugiere que querría escribir un int64_t en una cadena, mientras que su código hizo lo contrario (la lectura de una cadena hexadecimal en un int64_t). Respondí "en ambos sentidos":

La cabecera <inttypes.h> ha macros de conversión para manejar los tipos ..._t con seguridad:

#include <stdio.h> 
#include <inttypes.h> 

sprintf(str, "%016" PRIX64, int64); 

o (si eso es precisamente lo que estamos tratando de hacer), a la inversa :

#include <stdio.h> 
#include <inttypes.h> 

sscanf(str, "%" SCNx64, &int64); 

Tenga en cuenta que no se puede hacer cumplir las anchuras etc., con la familia scanf() función. Analiza lo que obtiene, lo que puede generar resultados no deseados cuando la entrada no se ajusta al formato esperado. Ah, y la familia de funciones scanf() solo sabe (minúsculas) "x", no (mayúsculas) "X".

Cuestiones relacionadas