Reputation: 730
I have problem to solve and have no idea how to do that. My program receives from serial port string with hex value (like DFF7DF). I need to convert it to binary form, discard first four bits, take fifth bit as sign bit and next 12 bits as a value.
I need to get value as normal INT.
I was able to make such program in MATLAB, but I need C++ to be able to run it on my linux arm board.
Thanks in advance for help! Marcin
Upvotes: 4
Views: 3100
Reputation: 68033
The question is tagged C++ but everyone is using C strings. Here's how to do it with a C++ STL string
std::string s("DFF7DF");
int val;
std::istringstream iss(s);
iss >> std::setbase(16) >> val;
int result = val & 0xFFF; // take bottom 12 bits
if (val & 0x1000) // assume sign + magnitude encoding
result = - result;
(The second "bit-fiddling" part isn't clear from your question. I'll update the answer if you clarify it.)
Upvotes: 1
Reputation: 33395
You have to check your machine type for endian-ness but this is basically the idea.
const char * string = "DFF7DF";
const unsigned char second_nibble = hex_to_int (string[1]);
const unsigned char third_nibble = hex_to_int (string[2));
const unsigned char fourth_nibble = hex_to_int (string[2));
int sign = second_nibble & (1<<3) ? -1 : 1;
unsigned value = unsigned (second_nibble & ~(1<<3)) << 12-3; // Next three bits are in second nibble
value |= (unsigned(third_nibble)<<1) | (fourth_nibble&1); // Next 9 bits are in the next two nibbles.
Make sure you perform your bit-shift operators on unsigned
types.
Upvotes: 0
Reputation: 43508
You could do something like:
unsigned long value = strtoul("DFF7DF", NULL, 16);
value >>= 4; // discard first four bits
printf("Minus sign: %s\n", value & 1 ? "yes" : "no");
printf("Value: %lu\n", (value & 0x1FFF) >> 1);
long newvalue = (value & 1 ? -1 : 1) * ((value & 0x1FFF) >> 1);
Upvotes: 5
Reputation: 106912
The correct answer depends on a few conventions - is the hex string big-endian or little-endian? Do you start counting bits from the most significant or the least significat bit? Will there always be exactly 6 hex characters (24 bits)?
Anyways, here's one solution for a big-endian, always-24-bits, counting from most significant bit. I'm sure you'll be able to adapt it if some of my assumptions are wrong.
int HexToInt(char *hex)
{
int result = 0;
for(;*hex;hex++)
{
result <<= 4;
if ( *hex >= '0' && *hex <= '9' )
result |= *hex-'0';
else
result |= *hex-'A';
}
return result;
}
char *data = GetDataFromSerialPortStream();
int rawValue = HexToInt(data);
int sign = rawValue & 0x10000;
int value = (sign?-1:1) * ((rawValue >> 4) & 0xFFF);
Upvotes: 2
Reputation: 2326
Here's a pattern to follow:
const char* s = "11";
istringstream in(string(s, 3));
unsigned i=0;
in >> hex >> i;
cout << "i=" << dec << i << endl;
The rest is just bit-shifting.
Upvotes: -1