11
votes

Convertir Adresse MAC STD :: String dans UINT64_T

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.

Alors, pouvez-vous me montrer un bon moyen propre pour convertir xxx

dans un uint64_t ?

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é!


9 commentaires

+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 () ...


J'ai essayé de trouver une solution élégante qui supprime tous les caractères ':' , PreXend "0x" (céder "0x00001224364f" ), 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.


9 Réponses :


1
votes

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;
}


2 commentaires

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ë.



3
votes

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];


3 commentaires

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 () ignore silencieusement le débordement (



10
votes
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])
        );
}

8 commentaires

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) est une syntaxe C valide. Et ces personnes peuvent remplacer sscanf avec std :: sscanf . )


@MAXIM: STD :: String n'est pas valide C Syntaxe non valide, ni thort std :: runtime_error (...) . 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 probablement est 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 est éventuellement niché que l'alternative C ++ ici!


@LightnessRacesinorbit De nos jours, je suggère d'utiliser les versions std :: , car les versions C ++ sont modifiées pour respecter le système de type, voir développeurs.redhat.com/blog/2016/02/29/...



1
votes

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;
}


3 commentaires

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 ':' ...



1
votes

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;
}


3 commentaires

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 ().



1
votes

Une autre version plus rapide sans appeler des fonctions de la bibliothèque: xxx


0 commentaires

8
votes

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);
}


1 commentaires

<- C'est ce que j'ai eu quand je l'ai essayé. Qu'est-ce que cela signifie même?



1
votes

plus C ++ 11 voies sans entrée de données d'entrée: xxx

Exemple live < / a>


0 commentaires

1
votes

Vous pouvez également utiliser l'ASCII struct ether_addr routine de conversion ether_aton , ou sa version thread-safe ether_aton_r (GNU extension). < Pré> xxx


0 commentaires