【问题标题】:Convert BYTE array into unsigned long long int将 BYTE 数组转换为 unsigned long long int
【发布时间】:2018-02-02 13:28:06
【问题描述】:

我正在尝试将 BYTE 数组转换为等效的 unsigned long long int 值,但我的编码没有按预期工作。请帮助修复它或建议一种替代方法。

额外信息:这 4 个字节组合成一个十六进制数,输出一个等效的十进制数。假设给定的 byteArray= {0x00, 0xa8, 0x4f, 0x00},十六进制数是 00a84f00,等效的十进制数是 11030272。

#include <iostream>
#include <string>

typedef unsigned char BYTE;

int main(int argc, char *argv[])
{
  BYTE byteArray[4] = { 0x00, 0x08, 0x00, 0x00 };
  std::string str(reinterpret_cast<char*>(&byteArray[0]), 4);
  std::cout << str << std::endl;

  unsigned long long ull = std::strtoull(str.c_str(), NULL, 0);
  printf ("The decimal equivalents are: %llu", ull);


  return EXIT_SUCCESS;
}

我得到以下输出:

The decimal equivalents are: 0

虽然预期的输出是:

The decimal equivalents are: 2048

【问题讨论】:

  • 使用memcpy()
  • 等等,什么?您如何期望一个充满特殊字符的字符串可以转换为2048?至少使用{0x32,0x30,0x34,0x38}
  • 还可以考虑使用 C++ 变体(C++11 及更高版本)

标签: c++


【解决方案1】:

当您调用std::strtoull(str.c_str(), NULL, 0); 时,它提供的第一个参数相当于一个空字符串,因为字符串本质上是一个以空字符结尾的字符序列。

第二,std::strtoull()不转换字节序列,它转换字符串的字面意思。即你会得到2048std::strtoull("2048", NULL, 10)

另外需要注意的是unsigned long long 是 64 位数据类型,而您的字节数组仅提供 32 位。您需要用零填充其他 32 个字节才能获得正确的结果。我使用直接分配,但您也可以在此处使用std::memset()

你想做的是:

ull = 0ULL;
std::memcpy(&ull, byteArray, 4);

假设您的平台有little-endian,结果应该是2048

【讨论】:

  • c++std::fillstd::copy 更适合。
  • @MárioFeroldi 看起来像是 C++17 中的新东西。对不起,我不太熟悉谁;(
  • 这些算法已经成为标准多年了;它们不是 C++17 特性。
  • @user9059547 你忘了#include &lt;cstdlib&gt;#include &lt;cstring&gt;
  • @user9059547 您的预期输出错误。字节数组应该是{0x00, 0x4f, 0xa8, 0x00}。这是字节序问题。请参阅最后一段中的链接。
【解决方案2】:

您首先必须记住的是,字符串实际上是一个 null-terminated 字符串。其次,字符串是characters的字符串,这不是你所拥有的。第三个问题是你有一个 4 字节的数组,它对应于一个无符号的 32 位整数,并且你想要一个(至少)64 位的类型,即 8 个字节。

您可以通过一个临时变量、一个简单的std::memcpy 调用和一个赋值来解决所有这些问题:

uint32_t temp;
std::memcpy(&temp, byteArray, 4);
ull = temp;

当然,这假设endianness 是正确的。


请注意,我使用 std::memcpy 而不是 std::copy(或 std::copy_n),因为明确提到 std::memcpy 能够以这种方式绕过严格的别名,而我不认为 std::copy 函数是.此外,std::copy 函数更多地用于复制 元素 而不是匿名字节(即使它们也可以这样做,但语法更笨拙)。

【讨论】:

  • 如果您使用正确的迭代器(char *unsigned char *signed char *std::byte *),那么由于这些指针的属性,严格别名不是问题。
  • 我收到错误:即使在我的代码中包含 string.h 后,'memcpy' 也不是 'std' 的成员。
  • @MárioFeroldi 好吧,标准中明确引用了std::memcpy(或std::memmove)(第 6.9 节类型,第 2,3 段和脚注 43、44)就是为了这个目的。恕我直言,它也更干净(即使您必须包含&lt;cstring&gt;),但这是一个见仁见智的问题......
  • @MárioFeroldi 生成的程序集可能(没有优化)也不同:godbolt.org/g/awnj4T
  • @Bob__ std::copy 可能不仅仅是字节复制,因为它可能只是为给定的迭代器集选择适当的算法。
【解决方案3】:

鉴于答案是使用std::memcpy,我想指出有一种更惯用的方式来执行此操作:

char byteArray[] = { 0x00, 0x08, 0x00, 0x00 };
uint32_t cp;
std::copy(byteArray, byteArray + sizeof(cp), reinterpret_cast<char*>(&cp));

std::copy 类似于std::memcpy,但它是 C++ 的实现方式。

请注意,您需要将输出变量cp 的地址转换为以下之一:char *unsigned char *signed char *std::byte *,否则操作将不是面向字节的。

【讨论】:

  • 对于给定的 byteArray 集,此代码似乎可以正常工作,但如果我更改 byteArray,它不会按预期工作。 :(
  • BYTE byteArray[] = {0x00, 0xa8, 0x4f, 0x00};预期输出为:11030272
  • @user9059547 如果你的架构是 little-endian,那么它会被解释为 0x004fa800。将0xa80x4f 交换,你应该得到11030272。
猜你喜欢
  • 1970-01-01
  • 2018-05-02
  • 2016-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-19
  • 1970-01-01
  • 2016-07-29
相关资源
最近更新 更多