在C/ c++中处理十六进制值

Dealing with hex values in C/C++

本文关键字:处理 十六进制 c++      更新时间:2023-10-16

我使用winsock从网络上的另一台计算机接收值。它是一个TCP套接字,消息的前4个字节携带它的大小。消息的其余部分由服务器使用protobuf(来自google的协议缓冲区)格式化。

问题,我认为,似乎是服务器发送的值是十六进制值作为字符发送(即只有10接收0x10)。要接收这些值,我可以这样做:

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

,其中data_s为stringstream。然后,我可以使用protobuf中的parsefroerror (&data_s)方法并恢复我想要的信息。

我的问题是,这是非常非常长的(我有另一个实现使用QSock,我不能使用我的项目,但这是快得多,所以没有问题在服务器端)。

我尝试了很多东西,我从这里和互联网上的任何地方(使用字节数组,字符串),但没有工作。

我还有其他选择吗?

感谢您的宝贵时间和宝贵意见;)

不确定这是否有任何用处,但我以前使用过类似的协议(前4个字节持有长度的int,其余部分使用protobuf编码),为了解码它,我做了这样的事情(可能不是最有效的解决方案,由于附加到字符串):

// 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)
}

我不会使用流操作符。它们用于格式化数据,这不是你想要的。

可以将接收到的值保存在char类型(字节向量)的std::vector中。这实际上就是一个动态数组。如果你想继续使用字符串流,你可以使用stringstream::write函数,它接受一个缓冲区和一个长度。您应该有从调用recv中接收到的缓冲区和字节数。

如果你想使用vector方法,你可以使用std::copy来使它更简单。

#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));

你的问题有点模棱两可。让我们以你为榜样。您接收到作为字符的10,并且希望将其作为十六进制数检索。

假设recv会给你这个字符串,你可以这样做。

首先让它以null结尾:

bytesreceived[msg_size] = '';

,那么你可以很容易地从这个缓冲区中读取值,使用标准的字符串*scanf函数:

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

好了!

编辑:如果您以相反顺序收到数字(因此0110),可能您最好的选择是手动转换它:

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;
}

这只是一个明显的例子。在现实中,你可以用移位来做,而不是乘法。

buffer是什么数据类型?

整个事情看起来像一个伟大的无操作,因为operator<<(stringstream&, char)忽略了基本说明符。hex说明符只影响非字符整型的格式化。当然,您不希望将文本数据传递给protobuf。

只需将buffer指针交给protobuf,就完成了。

好的,让我们进入黑暗:假设您的入口流是"71F4E81DA...",并且您想将其转换为字节流{ 0x71, 0xF4, 0xE8, ...}。然后,我们可以按照如下方式从字符字面量组合字节:

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);
}

这里我们使用了一个小的辅助函数:

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
}