C++ converting a mac id string into an array of uint8_t

前端 未结 4 1022
小蘑菇
小蘑菇 2021-01-15 17:42

I want to read a mac id from command line and convert it to an array of uint8_t values to use it in a struct. I can not get it to work. I have a vector of stri

相关标签:
4条回答
  • 2021-01-15 18:19

    Your problem may be in the output of the parsed data. The "<<" operator makes decisions on how to display data based on the data type passed it, and uint8_t may be getting interpretted as a char. Make sure you cast the array values to ints when printing, or investigate in a debugger.

    The sample program:

    uint8_t tgt_mac[6] = {0};
    std::stringstream ss( "AA:BB:CC:DD:EE:11" );
    char trash;
    
    for ( int i = 0; i < 6; i++ )
    {
        int foo;
        ss >> std::hex >> foo >> trash;
        tgt_mac[i] = foo;
        std::cout << std::hex << "Reading: " << foo << std::endl;
    }
    
    std::cout << "As int array: " << std::hex
        << (int) tgt_mac[0]
        << ":"
        << (int) tgt_mac[1]
        << ":"
        << (int) tgt_mac[2]
        << ":"
        << (int) tgt_mac[3]
        << ":"
        << (int) tgt_mac[4]
        << ":"
        << (int) tgt_mac[5]
        << std::endl;
    std::cout << "As unint8_t array: " << std::hex
        << tgt_mac[0]
        << ":"
        << tgt_mac[1]
        << ":"
        << tgt_mac[2]
        << ":"
        << tgt_mac[3]
        << ":"
        << tgt_mac[4]
        << ":"
        << tgt_mac[5]
        << std::endl;
    

    Gives the following output ( cygwin g++ )

    Reading: aa
    Reading: bb
    Reading: cc
    Reading: dd
    Reading: ee
    Reading: 11
    As int array: aa:bb:cc:dd:ee:11
    As unint8_t array: ª:»:I:Y:î:◄
    
    0 讨论(0)
  • 2021-01-15 18:21

    First I want to point out that I think @Steven's answer is a very good one - indeed I noticed the same: the values are correct, but the output looks awkward. This is due to ostream& operator<<( ostream&, unsigned char ) being used, since the uint8_t type you used is a typedef for unsigned char (as I found in the linux man pages). Note that on VC++, the typedef isn't there, and you have to use unsigned __int8 instead (which will also route you to the char specialization).

    Next, you can test your code like this (output-independent):

    assert( uint8_t( parseHex( "00" ) ) == uint8_t(0) );
    assert( uint8_t( parseHex( "01" ) ) == uint8_t(1) );
    //...
    assert( uint8_t( parseHex( "ff" ) ) == uint8_t(255) );
    

    In addition to Steven's answer, I just want to point out the existence of the transform algorithm, which could still simplify your code.

    for( int j = 0 ; j < v.size() ; j++ ){
      tgt_mac[j] = parseHex(v.at(j)); 
    }
    

    Writes in one line:

    std::transform( v.begin(), v.end(), tgt_mac, &parseHex );
    

    (And I know that hasn't to do with the question...)

    (See codepad.org for what it then looks like)

    0 讨论(0)
  • 2021-01-15 18:22

    I think you are using the std::hex in the wrong place:

    #include <sstream>
    #include <iostream>
    
    int main()
    {
        std::string     h("a5");
        std::stringstream   s(h);
        int x;
    
        s >> std::hex >> x;
        std::cout << "X(" << x << ")\n";
    }
    
    0 讨论(0)
  • 2021-01-15 18:26

    I hate to answer this in this fashion, but sscanf() is probably the most succinct way to parse out a MAC address. It handles zero/non-zero padding, width checking, case folding, and all of that other stuff that no one likes to deal with. Anyway, here's my not so C++ version:

    void
    parse_mac(std::vector<uint8_t>& out, std::string const& in) {
        unsigned int bytes[6];
        if (std::sscanf(in.c_str(),
                        "%02x:%02x:%02x:%02x:%02x:%02x",
                        &bytes[0], &bytes[1], &bytes[2],
                        &bytes[3], &bytes[4], &bytes[5]) != 6)
        {
            throw std::runtime_error(in+std::string(" is an invalid MAC address"));
        }
        out.assign(&bytes[0], &bytes[6]);
    }
    
    0 讨论(0)
提交回复
热议问题