开发者

Dealing with hex values in C/C++

开发者 https://www.devze.com 2023-03-31 04:57 出处:网络
I receive values using winsock from another computer on the network. It is a TCP socket, with the 4 first bytes of the message carrying its size. The rest of the message is formatted by the server usi

I receive values using winsock from another computer on the network. It is a TCP socket, with the 4 first bytes of the message carrying its size. The rest of the message is formatted by the server using protobuf (protocol buffers from google).

The problemn, I think, is that it seems that the values sent by the server are hex values sent as char (ie only 10 received for 0x10). To receive the values, I do this :

bytesreceived = recv(sock, buffer, msg_size, 0);
for (int i=0;i<bytesreceived;i++) 
{
    data_s << hex << buffer[i];
}

where data_s is a stringstream. Them I can use the ParseFromIstream(&data_s) method from protobuf and recover the information I want.

The problem that I have is that this is VERY VERY long (I got another implementation using QSock taht I can't开发者_JS百科 use for my project but which is much faster, so there is no problem on the server side).

I tried many things that I took from here and everywhere on the internet (using Arrays of bytes, strings), but nothing works.

Do I have any other options ?

Thank you for your time and comments ;)


not sure if this will be of any use, but I've used a similar protocol before (first 4 bytes holds an int with the length, rest is encoded using protobuf) and to decode it I did something like this (probably not the most efficient solution due to appending to strings):

// Once I've got the first 4 bytes, cast it to an int:
int msgLen = ntohl(*reinterpret_cast<const int*>(buffer));

// Check I've got enough bytes for the message, if I have then 
// just parse the buffer directly
MyProtobufObj obj;
if( bytesreceived >= msgLen+4 )
{
  obj.ParseFromArray(buffer+4,msgLen);
}
else
{
  // just keep appending buffer to an STL string until I have 
  // msgLen+4 bytes and then do
  // obj.ParseFromString(myStlString)
}


I wouldn't use the stream operators. They're for formatted data and that's not what you want.

You can keep the values received in a std::vector with the char type (vector of bytes). That would essentially just be a dynamic array. If you want to continue using a string stream, you can use the stringstream::write function which takes a buffer and a length. You should have the buffer and number of bytes received from your call to recv.

If you want to use the vector method, you can use std::copy to make it easier.

#include <algorithm>
#include <iterator>
#include <vector>

char buf[256];
std::vector<char> bytes;
size_t n = recv(sock, buf, 256, 0);
std::copy(buf, buf + n, std::back_inserter(bytes));


Your question is kind of ambiguous. Let's follow your example. You receive 10 as characters and you want to retrieve this as a hex number.

Assuming recv will give you this character string, you can do this.

First of all make it null terminated:

bytesreceived[msg_size] = '\0';

then you can very easily read the value from this buffer using standard *scanf function for strings:

int hexValue;
sscanf(bytesreceived, "%x", &hexValue);

There you go!

Edit: If you receive the number in reverse order (so 01 for 10), probably your best shot is to convert it manually:

int hexValue = 0;
int positionValue = 1;
for (int i = 0; i < msg_size; ++i)
{
    int digit = 0;
    if (bytesreceived[i] >= '0' && bytesreceived[i] <= '9')
        digit = bytesreceived[i]-'0';
    else if (bytesreceived[i] >= 'a' && bytesreceived[i] <= 'f')
        digit = bytesreceived[i]-'a';
    else if (bytesreceived[i] >= 'A' && bytesreceived[i] <= 'F')
        digit = bytesreceived[i]-'A';
    else // Some kind of error!
        return error;
    hexValue += digit*positionValue;
    positionValue *= 16;
}

This is just a clear example though. In reality you would do it with bit shifting for example rather than multiplying.


What data type is buffer?

The whole thing looks like a great big no-op, since operator<<(stringstream&, char) ignores the base specifier. The hex specifier only affects formatting of non-character integral types. For certain you don't want to be handing textual data to protobuf.

Just hand the buffer pointer to protobuf, you're done.


OK, a shot into the dark: Let's say your ingress stream is "71F4E81DA...", and you want to turn this into a byte stream { 0x71, 0xF4, 0xE8, ...}. Then we can just assemble the bytes from the character literals as follows, schematically:

char * p = getCurrentPointer();

while (chars_left() >= 2)
{
  unsigned char b;
  b  = get_byte_value(*p++) << 8;
  b += get_byte_value(*p++);

  output_stream.insert(b);
}

Here we use a little helper function:

unsigned char get_byte_value(char c)
{
  if ('0' <= c && c <= '9') return c - '0';
  if ('A' <= c && c <= 'F') return 10 + c - 'A';
  if ('a' <= c && c <= 'f') return 10 + c - 'a';

  return 0;  // error
}
0

精彩评论

暂无评论...
验证码 换一张
取 消