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";
}
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";
}
when i do a cout int the parse function i get correct values but when i assign them to the uint8_t array they get messed up. i tried your suggestion it works in the function but they still get messed up when i assign them.
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:î:◄
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)
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]);
}