Baldrick
Baldrick

Reputation: 11020

c++ how to convert my command line argument (MAC Address) to unsigned char

I have a program and I want to take a command line argument of a MAC address like "./myapp 00:11:22:33:44:55"

Later on the MAC address is used for struct sockaddr_ll.sll_addr in an unsigned char array, each element is one octet of the MAC address. This function (found on a blog) takes the command line argument and seperates it using the colon ":" as the delimiter;

void StringExplode(string str, string separator, vector<string>* results){
    int found;
    found = str.find_first_of(separator);
    while(found != string::npos){
        if(found > 0){
            results->push_back(str.substr(0,found));
        }
        str = str.substr(found+1);
        found = str.find_first_of(separator);
    }
    if(str.length() > 0){
        results->push_back(str);
    }
}

My code taking in the command line argument looks like this;

unsigned char MAC[6];
vector<string> R;
string thisstring = argv[2];
StringExplode(thisstring, ":", &R);
MAC[0] = (unsigned char)atoi(R[0].c_str());
MAC[1] = (unsigned char)atoi(R[1].c_str());
MAC[2] = (unsigned char)atoi(R[2].c_str());
MAC[3] = (unsigned char)atoi(R[3].c_str());
MAC[4] = (unsigned char)atoi(R[4].c_str());
MAC[5] = (unsigned char)atoi(R[5].c_str());
printf("Ethernet %02x:%02x:%02x:%02x:%02x:%02x\n",MAC[0],MAC[1],MAC[2],MAC[3],MAC[4], MAC[5]);

However, this prints out "Ethernet 00:0b:16:21:2c:37". Is this because atoi() is wrapping around? I can't seem to pin point the issue here, however, I feel this probably is a bad way of doing things. I'm new to c++ but even to me this feels long winded so I expect someone of the keyboard heros here will be able to explain just how bad it is, and hopefully how I could make this more efficient.

Thank you.

Upvotes: 2

Views: 2951

Answers (3)

juanchopanza
juanchopanza

Reputation: 227618

The problem is that you are reading in strings representing hexadecimal numbers as if they were decimal. C++11 string to integer conversion functions have a parameter where you can specify the base of the input, so to convert a hex string to an unsigned integer you can do this:

unsigned int i2 = std::stoi("ff", nullptr, 16); // input is base 16

See stoul, stoull, stol, stoi.

Upvotes: 2

Rup
Rup

Reputation: 34418

The problem is that you're parsing the octets as decimal numbers not hex - 11 = 0xb, 22 = 0x16, etc.

I'm not sure what the most C++ way of doing this is, but you can e.g. use strtoul with a base argument:

for(int i = 0; (i < 6) && (i < R.size()); ++i) {
    MAC[i] = (unsigned char)strtoul(R[i].c_str(), NULL, 16);
}

Upvotes: 3

besworland
besworland

Reputation: 765

From my point of view everything is OK. The only point is that you are printing decimal values in hexadecimal view. Convert input values to hexadecimal.

Upvotes: 1

Related Questions