将uint8_t转换为其二进制表示

时间:2016-06-11 08:11:58

标签: c++ c serialization casting uint8t

我有一个uint8_t类型的变量,我想序列化并写入一个文件(这应该是非常便携的,至少对于Windows来说,这正是我的目标)。

尝试将其写入二进制形式的文件中,我遇到了这个工作片段:

uint8_t m_num = 3;
unsigned int s = (unsigned int)(m_num & 0xFF);
file.write((wchar_t*)&s, 1); // file = std::wofstream

首先,让我确保我理解这个代码片段的作用 - 它需要我的var(基本上是一个无符号字符,长度为1个字节),将其转换为unsigned int(长度为4个字节,以及不太可移植),并使用& 0xFF “提取”只有最不重要的字节。

现在,有两件事我不明白:

  1. 为什么首先将其转换为unsigned int,为什么我不能简单地执行类似的事情 file.write((wchar_t*)&m_num, 1);reinterpret_cast<wchar_t *>(&m_num)? (Ref
  2. 如何序列化更长的类型,例如uint64_t(长度为8个字节)? unsigned int在这里可能还是不够。

2 个答案:

答案 0 :(得分:1)

uint8_t为1个字节,与char

相同

wchar_t在Windows中为2个字节,在Linux中为4个字节。它还取决于字节顺序。如果担心可移植性,则应避免使用wchar_t

您可以使用std::ofstream。 Windows有std::ofstream的附加版本,它接受UTF16文件名。这样,您的代码与Windows UTF16文件名兼容,您仍然可以使用std::fstream。例如

int i = 123;
std::ofstream file(L"filename_in_unicode.bin", std::ios::binary);
file.write((char*)&i, sizeof(i)); //sizeof(int) is 4
file.close();
...
std::ifstream fin(L"filename_in_unicode.bin", std::ios::binary);
fin.read((char*)&i, 4); // output: i = 123

这相对简单,因为它只存储整数。这将适用于不同的Windows系统,因为Windows始终是little-endian,int大小始终为4.

但是有些系统是大端的,你必须单独处理它。

如果使用标准I / O,例如fout << 123456,则整数将存储为文本“123456”。标准I / O是兼容的,但它需要更多的磁盘空间,并且可能会慢一些。

它的兼容性与性能。如果您有大量数据(几兆字节或更多),并且您将来可以处理兼容性问题,那么继续编写字节。否则,使用标准I / O会更容易。性能差异通常无法衡量。

答案 1 :(得分:0)

unit8_t值写入wofstream是不可能的,因为wofstream只能写宽字符而根本不处理二进制值。

如果您要做的是写一个代表0到255之间代码点的宽字符,那么您的代码是正确的。

如果要将二进制数据写入文件,则最近的等效数据为ofstream,这将允许您写入字节。

回答你的问题:

  1. wofstream::write写入宽字符,而不是字节。如果重新解释m_num的地址作为宽字符的地址,您将编写一个16位或32位(取决于平台)宽字符,其中第一个字节(即最不重要)或者最重要的,取决于平台)是m_num的值,剩余的字节是在m_num之后发生在内存中的任何事件。根据宽字符的字符编码,这甚至可能不是有效字符。即使有效,这在很大程度上是无稽之谈。 (如果wofstream::write需要宽字符对齐而不是字节对齐的输入,或者m_num后面紧跟不可读的内存,则还有其他可能的问题。

  2. 如果你使用wofstream那么这就是一团糟,而我却没有解决它。如果切换到面向字节的ofstream,那么您有两个选择。 1。如果您只是在同一系统上阅读该文件,file.write(&myint64value,sizeof(myint64value))将起作用。写入64位值的字节的顺序将是未定义的,但是当您回读时将使用相同的顺序,因此这并不重要。 不要尝试做一些与wofstream类似的事情,因为它很危险! 2. 分别提取myint64value的8个字节中的每一个(向右移8位的倍数,然后取下6位),然后写入。这是完全可移植的,因为您可以控制写入字节的顺序。