互联网上有几篇文章建议您应该std::vector<unsigned char>
对二进制数据使用或类似的东西。
但我更喜欢它的std::basic_string
变体,因为它提供了许多方便的字符串操作函数。而且 AFAIK,自 C++11 以来,该标准保证了每个已知的 C++03 实现已经做了:std::basic_string
将其内容连续存储在内存中。
乍一看,std::basic_string<unsigned char>
可能是一个不错的选择。
但是,我不想使用std::basic_string<unsigned char>
,因为几乎所有操作系统功能都只接受char*
,因此需要进行显式转换。此外,字符串文字是,所以每次我将字符串文字分配给我的二进制字符串时,const char*
我都需要显式转换,我也想避免这种情况。const unsigned char*
此外,用于读取和写入文件或网络缓冲区的函数同样接受char*
和const char*
指针。
剩下std::string
的就是std::basic_string<char>
.
使用二进制数据唯一潜在的剩余问题(我可以看到)std::string
是std::string
使用char
(可以签名)。
char
, signed char
, 和unsigned char
是三种不同的类型,char
可以是无符号的或有符号的。
11111111b
因此,当从 char 返回的实际字节值std::string:operator[]
,并且您想检查它的值时,它的值可以是255
(如果char
是无符号的)或者它可能是“负数”(如果char
是有符号的,取决于您的数字表示)。
类似地,如果您想将实际字节值显式附加11111111b
到 a std::string
,则简单地附加(char) (255)
可能是实现定义的(甚至引发信号)如果char
已签名并且int
tochar
对话导致溢出。
那么,有没有一种安全的方法来解决这个问题,再次使std::string
二进制安全?
§3.10/15 规定:
如果程序尝试通过非下列类型之一的泛左值访问对象的存储值,则行为未定义:
- [...]
- 与对象的动态类型相对应的有符号或无符号类型,
- [...]
- char 或 unsigned char 类型。
如果我理解正确的话,它似乎允许使用unsigned char*
指针来访问和操作 a 的内容,std::string
并使 this 也是定义良好的. 它只是将位模式重新解释为,而没有任何更改或信息丢失,后者即因为 a 、和unsigned char
中的所有位都必须用于值表示。char
signed char
unsigned char
然后,我可以使用unsigned char*
对内容的这种解释std::string
作为访问和更改[0, 255]
范围内字节值的一种方式,以一种明确定义和可移植的方式,而不管其char
自身的符号性如何。
这应该可以解决由潜在签名引起的任何问题char
。
我的假设和结论正确吗?
此外,unsigned char*
相同位模式(即11111111b
或10101010b
)的解释是否保证在所有实现中都相同?换句话说,标准是否保证“通过眼睛看unsigned char
”,相同的位模式总是导致相同的数值(假设一个字节中的位数相同)?
因此,我可以安全地(即,没有任何未定义或实现定义的行为)std::string
用于在 C++11 中存储和操作二进制数据吗?