【问题标题】:How to convert a 48-bit byte array into an 64-bit integer in C?如何在 C 中将 48 位字节数组转换为 64 位整数?
【发布时间】:2012-05-15 23:58:50
【问题描述】:

我有一个大小为 6 的无符号字符数组。字节数组的内容是一个整数(4096* 自 Unix 时间以来的秒数)。我知道字节数组是大端的。

是否有 C 中的库函数可用于将此字节数组转换为 int_64 还是必须手动执行?

谢谢!

PS:以防万一您需要更多信息,是的,我正在尝试解析 Unix 时间戳。 Here 是我处理的时间戳的格式规范。

【问题讨论】:

  • 没有标准的 C 函数可以做到这一点。不过,有可能使用这种格式的任何库都提供了一个函数。
  • 您必须手动完成,这很容易。由于您正在涉足字节排序,我建议您阅读this Rob Pike 的博客文章。对你有帮助的代码都包含在文章中,不要直接去阅读它。

标签: c endianness unix-timestamp type-conversion


【解决方案1】:

C99 实现可以提供uint64_t(如果没有正好是 64 位的本机固定宽度整数,则不必提供),在这种情况下,您可以使用:

#include <stdint.h>

unsigned char data[6] = { /* bytes from somewhere */ };
uint64_t result = ((uint64_t)data[0] << 40) |
                  ((uint64_t)data[1] << 32) |
                  ((uint64_t)data[2] << 24) |
                  ((uint64_t)data[3] << 16) |
                  ((uint64_t)data[4] << 8)  |
                  ((uint64_t)data[5] << 0);

如果您的 C99 实现不提供 uint64_t,您仍然可以使用 unsigned long long 或(我认为)uint_least64_t。无论主机的本地字节序如何,这都将起作用。

【讨论】:

  • uint_least64_t 在 C99 中是必需的。而且 C89 没有保证 64 位整数:D
【解决方案2】:

你试过了吗:

unsigned char a [] = {0xaa,0xbb,0xcc,0xdd,0xee,0xff};
unsigned long long b = 0;
memcpy(&b,a,sizeof(a)*sizeof(char));
cout << hex << b << endl;

或者您可以手动完成,这样可以避免一些特定于架构的问题。

我建议使用普通整数运算(求和和移位),而不是尝试模拟内存块排序,这在兼容性方面并不比上述解决方案更好。

【讨论】:

  • 是的。预处理器条件可能有助于选择正确的方法(如果性能很关键)。
  • 不不不不。请参阅 Francisco Soto 的回答中链接的博客文章,了解为什么在这些情况下应避免预处理器条件。
  • 我想我今天学到的东西比原来的海报还多:p
【解决方案3】:

我认为最好的方法是使用联合。

union time_u{
    uint8_t data[6];
    uint64_t timestamp;
}

然后您可以通过引用将该内存空间用作字节数组或 uint64_t

union time_u var_name;
var_name.data[i]
var_name.timestamp

【讨论】:

  • 这行不通,因为问题指出字节数组是大端字节序。
【解决方案4】:

这是一个将其转换为 64 位的方法:

uint64_t
convert_48_to_64(uint8_t *val_ptr){
  uint64_t ret = 0;
  uint8_t *ret_ptr = (uint8_t *)&ret;

  for (int i = 0; i < 6; i++) {
      ret_ptr[5-i] = val_ptr[i];
  }
  return ret;
 }

 convert_48_to_64((uint8_t)&temp);  //temp is in 48 bit

例如:num_in_48_bit = 77340723707904;这个数字在48位二进制为:0100 0110 0101 0111 0100 1010 0101 1101 0000 0000 0000 0000转换的64位二进制会后:0000 0000 0000 0000 0000 0000 0000 0000 0101 1101 0100 1010 0101 0111 0100 0110比方说val_ptr店num_in_48_bit 的基地址。由于指针类型转换为 uint8_t,递增 val_ptr 将为您提供下一个字节。循环并逐字节复制值。请注意,我也在按字节顺序处理网络。

【讨论】:

  • 你能解释一下吗?
  • 你能用这个解释编辑你的答案吗?它将提供更多信息。
【解决方案5】:

你可以使用打包选项

#pragma pack(1)

__attribute__((packed))

取决于编译器

typedef struct __attribute__((packed))
{
    uint64_t u48: 48;
} uint48_t;

uint48_t data;

memcpy(six_byte_array, &data, 6);
uint64_t result = data.u48;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-06
    • 1970-01-01
    相关资源
    最近更新 更多