在C中来回转换64位unsigned int到char缓冲区

时间:2017-05-07 12:01:01

标签: c string 64-bit

我的目标是通过网络发送数据报,该数据报以网络字节顺序的64位无符号整数开头。首先,我使用宏将数字转换为big-endian:

#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))

然后我将它序列化为一个缓冲区:

unsigned char * serialize_uint64(unsigned char *buffer, uint64_t value) {
  printf("**** seriializing PRIu64 value = %"PRIu64"\n", value);
  int i;
  for (i = 0; i < 8; i++)
    buffer[i] = (value >> (56 - 8 * i)) & 0xFF;
  for (i = 0; i < 8; i++)
    printf("bufer[%d] = %x\n", i, buffer[i]);

  return buffer + 8;
}

然后我用

反序列化它
uint64_t deserialize_uint64(unsigned char *buffer) {
  uint64_t res = 0;
  printf("*** deserializing buffer:\n");
  int i;
  for (i = 0; i < 8; i++)
    printf("bufer[%d] = %x\n", i, buffer[i]);
  for (i = 0; i < 8; i++)
    res |= buffer[i] << (56 - 8 * i);


  return res;
}

它似乎适用于小整数,但以下测试代码无法正常工作:

uint64_t a = (uint64_t) time(NULL);
printf("PRIu64: a =%"PRIu64"\n", a);

uint64_t z = htonll(a);
uint64_t zz = ntohll(z);
printf("z = %"PRIu64" ==> zz = %"PRIu64" \n", z, zz);

unsigned char buffer[1024];
serialize_uint64(buffer, z);
uint64_t b = deserialize_uint64(buffer);
uint64_t c = ntohll(g);

我得到了

a = 1494157850
htonll(a) = 1876329069679738880 ==> ntohll(htonll(a)) = 1494157850 
**** seriializing PRIu64 value = 1876329069679738880
bufer[0] = 1a
bufer[1] = a
bufer[2] = f
bufer[3] = 59
bufer[4] = 0
bufer[5] = 0
bufer[6] = 0
bufer[7] = 0
*********
*** deserializing buffer:
bufer[0] = 1a
bufer[1] = a
bufer[2] = f
bufer[3] = 59
bufer[4] = 0
bufer[5] = 0
bufer[6] = 0
bufer[7] = 0
===> res = 436866905
c = 6417359100811673600

似乎缓冲区没有捕获更大的数字......

1 个答案:

答案 0 :(得分:1)

您的序列化程序基本上是

unsigned char *serialize_u64(unsigned char *buffer, uint64_t value)
{
    buffer[7] = value & 0xFF;
    value >>= 8;
    buffer[6] = value & 0xFF;
    value >>= 8;
    buffer[5] = value & 0xFF;
    value >>= 8;
    buffer[4] = value & 0xFF;
    value >>= 8;
    buffer[3] = value & 0xFF;
    value >>= 8;
    buffer[2] = value & 0xFF;
    value >>= 8;
    buffer[1] = value & 0xFF;
    value >>= 8;
    buffer[0] = value & 0xFF;
    return buffer + 8;
}

并将value从本机字节顺序序列化为网络字节顺序;不需要宏。

所以,看起来OP的serialize_uint64()应该可以正常工作。只是根本不应该使用字节顺序宏。

OP deserialize_uint64()应在移位前将buffer[i]强制转换为(uint64_t),以确保移位结果为64位。就个人而言,我更喜欢将反序列化器编写为

unsigned char *serialize_u64(unsigned char *buffer, uint64_t *valueptr)
{
    uint64_t value = buffer[0];
    value <<= 8;
    value |= buffer[1];
    value <<= 8;
    value |= buffer[2];
    value <<= 8;
    value |= buffer[3];
    value <<= 8;
    value |= buffer[4];
    value <<= 8;
    value |= buffer[5];
    value <<= 8;
    value |= buffer[6];
    value <<= 8;
    value |= buffer[7];
    *valueptr = value;
    return buffer + 8;
}
如果OP使用res |= ((uint64_t)buffer[i]) << (56 - 8 * i);代替,则

执行与OP相同的操作。

同样,串行器和解串器都已经将数据转换为/从网络字节顺序转换为/到本机字节顺序;根本不应该使用字节顺序宏。