J'ai une adresse mac hexadécimale détenue dans une ficelle STD :: String. Quelle serait la meilleure façon de transformer cette adresse MAC dans un type d'entier détenu dans un uint64_t?
Je suis au courant de Stringstream, Sprintf, Atoi, etc. J'ai réellement écrit peu de fonctions de conversion avec les 2 premiers Ceux-ci, mais ils semblent plus bâcs que je le souhaiterais. P>
Alors, pouvez-vous me montrer un bon moyen propre pour convertir p> dans un uint64_t ? p> PS: Je n'ai pas d'installations de Boost / TR1 disponibles et ne pouvez pas les installer où le code sera réellement utilisé (ce qui est aussi pourquoi je n'ai pas copié collé une de mes tentatives, désolé à propos de ça!). Veuillez donc garder des solutions aux appels C / C ++ directement. Si vous avez une solution intéressante avec un appel système UNIX, je serais également intéressé! P> p>
9 Réponses :
Je ne peux penser à aucune astuce magique. Voici une tentative aléatoire qui peut être meilleure que ce que vous avez fait. C'est simpliste, mais je parie qu'il y a des solutions beaucoup plus rapides.
uint64_t mac2int(std::string s) {
uint64_t r=0;
std::string::iterator i;
std::string::iterator end = s.end();
for(i = s.begin; i != end; ++i) {
char let = *i;
if (let >= '0' && let <= '9') {
r = r*0xf + (let-'0');
} else if (let >= 'a' && let <= 'f') {
r = r*0xf + (let-'a'+10);
} else if (let >= 'A' && let <= 'F') {
r = r*0xf + (let-'A'+10);
}
}
return r;
}
Contrairement aux autres réponses, la mine accepte également "01-23-45-67-89-AB", "0123.4567.89AB" (à la fois valide) et "joyeux anniversaire à toi".
Strictement parler, les personnages 'A' '..' F 'et' A 'et' A '..' F »ne sont pas garantis d'avoir des représentations contiguës (les chiffres« 0 ».. '9' sont). En pratique, cela ne sera pas un problème; Même EBCDIC, qui ne fait pas l'alphabet contigu, fait 'A' .. 'F' et 'A' .. "F 'contiguë.
Utiliser SSCANF:
std::string mac = "00:00:12:24:36:4f";
unsigned u[6];
int c=sscanf(mac.c_str(),"%x:%x:%x:%x:%x:%x",u,u+1,u+2,u+3,u+4,u+5);
if (c!=6) raise_error("input format error");
uint64_t r=0;
for (int i=0;i<6;i++) r=(r<<8)+u[i];
// or: for (int i=0;i<6;i++) r=(r<<8)+u[5-i];
Que se passe-t-il si vous le nourrissez avec "ABC: DEF: 123: 456: 789"?
U [I] est défini sur Valeurs> 255. OP pourrait vérifier cela si nécessaire et donner un diagnostic. Malheureusement,% HHX ne l'attrape pas non plus, n'est-ce pas?
sscanf () code> ignore silencieusement le débordement (
uint64_t string_to_mac(std::string const& s) {
unsigned char a[6];
int last = -1;
int rc = sscanf(s.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx%n",
a + 0, a + 1, a + 2, a + 3, a + 4, a + 5,
&last);
if(rc != 6 || s.size() != last)
throw std::runtime_error("invalid mac address format " + s);
return
uint64_t(a[0]) << 40 |
uint64_t(a[1]) << 32 | (
// 32-bit instructions take fewer bytes on x86, so use them as much as possible.
uint32_t(a[2]) << 24 |
uint32_t(a[3]) << 16 |
uint32_t(a[4]) << 8 |
uint32_t(a[5])
);
}
Je peux presque garantir que quelqu'un vous criera pour fournir une solution de style C pour une question C ++ ...
Cela nécessite un format spécifique de l'adresse MAC, qui peut ou non être un problème.
Hé, si c'est rapide alors je suis heureux, quel que soit le type de solution. Je vais juste m'asseoir et voir ce que d'autres personnes aiment le mieux avant de choisir des réponses.
Je ne pense pas uint64_t (x) code> est une syntaxe C valide. Et ces personnes peuvent remplacer sscanf code> avec std :: sscanf code>. )
@MAXIM: STD :: String Code> n'est pas valide C Syntaxe non valide, ni thort std :: runtime_error (...) code>. La solution n'est pas censée être valide C, il arrive simplement d'utiliser une fonction de la bibliothèque C standard C (qui est incluse dans la bibliothèque C ++ standard).
@MAXIM: "C-style" ne signifie pas "seul code C valide". C ++ a ses propres conventions et idiomes, et c'est celles-ci que nous préférons voir au code C ++ sur les alternatives de style C! (Cependant, @oli, dans ce cas, std :: sscanf code> probablement est i> la meilleure approche. Ce n'est que marginalement de style c-style C, et non non plus non plus. )
@Tomalak: Je suis enclin à accepter que sscanf code> est éventuellement niché que l'alternative C ++ ici!
@LightnessRacesinorbit De nos jours, je suggère d'utiliser les versions std :: Code>, car les versions C ++ sont modifiées pour respecter le système de type, voir développeurs.redhat.com/blog/2016/02/29/...
Mes 2 centimes:
uint64_t ParseMac(const std::string& str)
{
std::istringstream iss(str);
uint64_t nibble;
uint64_t result(0);
iss >> std::hex;
while(iss >> nibble) {
result = (result << 8) + nibble;
iss.get();
}
return result;
}
Cela semble intéressant, +1 :)
hein, utilisation intelligente de Iss.get ().
Pas vraiment, car il n'effectue aucune vérification que le caractère mangé est ':' ...
Cela permettra de déplacer des chiffres hexagonaux jusqu'à ce que la chaîne s'épuise, ne prenez pas de soin des délimiteurs ou de la longueur totale. Mais il convertit la chaîne d'entrée au format uint64_t souhaité.
#include <string>
#include <stdint.h>
uint64_t cvt(std::string &v)
{
std::string::iterator i;
std::string digits = "0123456789abcdefABCDEF";
uint64_t result = 0;
size_t pos = 0;
i = v.begin();
while (i != v.end())
{
// search for character in hex digits set
pos = digits.find(*i);
// if found in valid hex digits
if (pos != std::string::npos)
{
// handle upper/lower case hex digit
if (pos > 0xf)
{
pos -= 6;
}
// shift a nibble in
result <<= 4;
result |= pos;
}
++i;
}
return result;
}
J'étais sur le point de critiquer la vitesse des chiffres.Find (), mais nous nous sommes alors rappelés que vous avez une longueur fixe de 16, qui convient à la cache ... c'est beaucoup plus vite.
Si la vitesse ultime était l'objectif, une table de recherche doit remplacer la chaîne des chiffres. J'utiliserais une table de 256 éléments UINT8_T avec les indices valides ayant une valeur inférieure à 16 et tous les autres peut-être 0xff.
Incidemment, je viens de vous rappeler une fonction standard qui effectue directement l'opération exacte de l'OP. C'est éther_aton ().
Une autre version plus rapide sans appeler des fonctions de la bibliothèque:
Ma solution (nécessite C ++ 11):
#include <string>
#include <cstdint>
#include <algorithm>
#include <stdlib.h>
uint64_t convert_mac(std::string mac) {
// Remove colons
mac.erase(std::remove(mac.begin(), mac.end(), ':'), mac.end());
// Convert to uint64_t
return strtoul(mac.c_str(), NULL, 16);
}
<- C'est ce que j'ai eu quand je l'ai essayé. Qu'est-ce que cela signifie même?
plus C ++ 11 voies sans entrée de données d'entrée:
Vous pouvez également utiliser l'ASCII struct ether_addr code> routine de conversion ether_aton code>, ou sa version thread-safe ether_aton_r code> (GNU extension). < Pré> xxx pré> p>
+1. Surpris que cela ne soit pas venu auparavant. Quel est le cas d'utilisation? Est-ce rare?
Je ne comprends pas le lien entre ne pas pouvoir utiliser Boost / TR1 et ne pas nous montrer vos tentatives.
Il suffit de traiter avec un grand réseau d'appareils et le Mac constitue un bon identifiant unique étant donné le scénario depuis sa mise en place. Tout est alimenté par XML, donc je reçois les valeurs en tant que texte lisible par l'homme, mais l'une des interfaces nécessite le Mac comme uint64_t (qui est compréhensible). J'ai été surpris que ce n'était pas là aussi: p
Il suffit de dire que les tentatives sont sur un système informatique que je ne peux pas accéder à partir de PC à compter de l'Internet :(
Vous avez un clavier et des yeux, n'est-ce pas? Vous ne pouvez pas écrire le code (que vous avez écrit vous-même en premier lieu!) Sans recourir à copier / coller?
Haha, oui - assez juste. J'ai pensé que c'était une fonction rapide que quelqu'un pourrait probablement une ou deux lignes d'une manière que je n'avais pas pensée. Mes voies étaient un peu chunky et je savais que quelqu'un d'autre viendrait avec quelque chose ... plus élégant? : p
Pour donc, nous préférons généralement la fixation du code existant pour fournir un nouveau code. Rentacoder.com est juste autour du coin ;-)
Vous pouvez probablement écrire une petite boucle soignée avec
strtoul () code> ...J'ai essayé de trouver une solution élégante qui supprime tous les caractères
':' code>, PreXend"0x" code> (céder"0x00001224364f" code " >), puis convertit le résultat en uint64_t. Peut-être que quelqu'un qui est plus familier avec la bibliothèque standard C ++ que je peux l'essayer.