2010-11-09 5 views
6

J'ai essayéComment convertir une chaîne hexadécimale en entier non signé 64bit (uint64_t) de manière rapide et sûre?

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

mais ne semble pas sûr. Y a-t-il un moyen rapide et sûr de faire le casting de type?

Merci ~

+0

Que voulez-vous dire par "pas sûr"? –

+1

Je ne sais pas. J'ai essayé d'utiliser ceci pour faire le casting parmi un grand nombre de chaînes hexadécimales, et parfois cela signalerait un défaut de segment. –

+0

Pourriez-vous montrer la déclaration et l'initialisation de 'str'? – Flinsch

Répondre

7

Ne vous préoccupez pas des fonctions de la famille scanf. Ils sont presque impossibles à utiliser de manière robuste. Voici une utilisation en toute sécurité générale 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 */ 
} 

Notez que strtoull accepte un préfixe 0x en option sur la chaîne, ainsi que des espaces initial en option et un caractère de signe (ou +-). Si vous souhaitez rejeter ces derniers, vous devez effectuer un test avant d'appeler strtoull, par exemple:

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

Si vous souhaitez également interdire les représentations trop longues de chiffres (des zéros à gauche), vous pouvez vérifier la condition suivante avant d'appeler strtoull:

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

Une chose à garder à l'esprit est que « les nombres négatifs » ne sont pas considérés comme hors de la plage de conversion; à la place, un préfixe de - est traité comme l'opérateur de négation unaire dans C appliqué à une valeur non signée, par exemple strtoull("-2", 0, 16) renverra ULLONG_MAX-1 (sans définir errno).

+0

De manière générale, je suis d'accord avec vos sentiments concernant la famille 'scanf()'. Ils * ont * un sens dans des environnements contrôlés, par ex. lire dans les fichiers que votre application a écrit lui-même – DevSolar

+0

@DevSolar: En effet, mon commentaire était destiné à répondre à la question de l'OP sur l'utilisation en toute sécurité, pas de conseils généraux. La famille 'scanf' fonctionne bien pour lire les fichiers Linux'/proc', par exemple. –

+0

'strtoull()' ne renverrait-il pas un type 'unsigned long long', qui n'est pas nécessairement un type 'uint64_t'? – GreySage

2

Votre titre (à l'heure actuelle) en contradiction avec le code que vous avez fourni. Si vous voulez faire ce que votre titre était à l'origine (convertir une chaîne en entier), vous pouvez utiliser cette réponse.


Vous pouvez utiliser la fonction strtoull, qui, contrairement à sscanf est une fonction spécifiquement orientée vers la lecture des représentations textuelles de nombres.

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

Selon moi, il veut convertir de l'entier en chaîne, pas vice versa. ;) – Flinsch

+1

@Flinsch, le titre a changé, mais son code d'origine suggère qu'il veut convertir de chaîne en entier. Je ne suis pas sûr que vous puissiez voir l'historique des modifications de la question, mais le titre indiquait à l'origine qu'il voulait convertir une chaîne en nombre entier. – dreamlax

+0

En fait, 'scanf()' et al. sont * définis * en termes de 'strtol()'. Pour une entrée décent à mi-chemin, ils sont fonctionnellement identiques en ce qui concerne les nombres d'analyse. J'admets que 'strtol()' gère l'échec plus gracieusement. – DevSolar

0

Au moment où je l'ai écrit cette réponse, votre titre a suggéré que vous voudriez écrire un int64_t dans une chaîne, tandis que votre code a fait le contraire (lire une chaîne hexagonale dans un int64_t). Je lui ai répondu « deux voies »:

La sécurité en-tête <inttypes.h> a des macros de conversion pour gérer les ..._t types:

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

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

Or (si tel est bien ce que vous essayez de faire), dans l'autre sens :

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

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

Notez que vous ne pouvez pas appliquer des largeurs etc. avec la famille de fonction scanf(). Il analyse ce qu'il obtient, ce qui peut produire des résultats non désirés lorsque l'entrée n'adhère pas au formatage attendu. Oh, et la famille de fonctions scanf() ne connaît que «x» (minuscules) et non «majuscule» («X»).

Questions connexes