将BYTE数组转换为无符号长整型int

4
我试图将一个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() - iBug
2
等等,什么?你怎么期望一个充满特殊字符的字符串可以转换成 2048?至少使用 {0x32,0x30,0x34,0x38} - user202729
还要考虑使用C++的变体(C++11及更高版本)。 - user202729
3个回答

3
当您调用std::strtoull(str.c_str(), NULL, 0);时,其提供的第一个参数等同于空字符串,因为字符串本质上是以null结尾的字符序列。
其次,std::strtoull()不使用字节序列进行转换,而是使用字符串的字面含义进行转换。例如,std::strtoull("2048", NULL, 10)将返回2048
另一个需要注意的事项是,unsigned long long是一个64位数据类型,而您的字节数组仅提供32位。您需要使用零来填充其他32个字节,以获得正确的结果。我使用直接赋值,但您也可以在这里使用std::memset()
您想要做的是:
ull = 0ULL;
std::memcpy(&ull, byteArray, 4);

假设你的平台采用 little-endian,则结果应为 2048

由于这是 [tag:c++],因此 std::fillstd::copy 更适合。 - Mário Feroldi
@MárioFeroldi 你能否提供一个例子? - user9059547
1
@user9059547 你忘记了 #include <cstdlib>#include <cstring> - iBug
在我包含了<cstring>之后,它可以处理给定的输出集,但不能处理另一个byteArray = {0x00, 0xa8, 0x4f, 0x00},期望输出:11030272。 - user9059547
1
@user9059547 你期望的输出是错误的。字节数组应该是 {0x00, 0x4f, 0xa8, 0x00}。这是一个大小端问题。请参考最后一段中的链接。 - iBug
显示剩余4条评论

3
你首先必须记住的是,字符串实际上是一个以空字符结尾的字符串。其次,字符串是一串字符,而不是你所拥有的内容。第三个问题是你有一个四字节的数组,对应于一个无符号32位整数,并且你想要一个至少为8字节的64位类型。

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

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

当然,这假设字节序是正确的。
请注意,我使用 std::memcpy 而不是 std::copy(或 std::copy_n),因为明确提到 std::memcpy 可以绕过严格别名的限制,而我认为 std::copy 函数没有这样的功能。此外,std::copy 函数更适用于复制元素,而不是匿名字节(即使它们也可以这样做,但语法更加笨重)。

如果您使用正确的迭代器(char *unsigned char *signed char *std::byte *),则由于这些指针的属性,严格别名不是问题。 - Mário Feroldi
我在我的代码中包含了string.h,但仍然出现错误:“memcpy”不是“std”的成员。 - user9059547
@MárioFeroldi 好的,std::memcpy(或std::memmove)明确地被标准引用(§6.9类型,第2、3段和脚注43、44)用于此目的。在我看来,这也更加清晰易懂(即使你必须包含<cstring>),但这是个人观点的问题... - Bob__
@MárioFeroldi 生成的汇编代码(未经优化)也可能不同:https://godbolt.org/g/awnj4T - Bob__
@Bob__ std::copy 可能不仅仅是字节复制,因为它可能会为给定的迭代器集合选择适当的算法。 - Mário Feroldi

2

考虑到答案使用了std::memcpy,我想指出有一种更加惯用的方法来执行此操作:

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

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

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


这段代码对于给定的byteArray似乎运行良好,但如果我更改我的byteArray,则无法按预期工作。 :( - user9059547
BYTE byteArray[] = {0x00, 0xa8, 0x4f, 0x00}; 的预期输出为:11030272 - user9059547
如果你的架构是小端模式,那么它将被解释为 0x004fa800。交换 0xa80x4f,你就会得到 11030272。 - Mário Feroldi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接