互联网上有几篇文章建议您应该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已签名并且inttochar对话导致溢出。
那么,有没有一种安全的方法来解决这个问题,再次使std::string二进制安全?
§3.10/15 规定:
如果程序尝试通过非下列类型之一的泛左值访问对象的存储值,则行为未定义:
- [...]
- 与对象的动态类型相对应的有符号或无符号类型,
- [...]
- char 或 unsigned char 类型。
如果我理解正确的话,它似乎允许使用unsigned char*指针来访问和操作 a 的内容,std::string并使 this 也是定义良好的. 它只是将位模式重新解释为,而没有任何更改或信息丢失,后者即因为 a 、和unsigned char中的所有位都必须用于值表示。charsigned charunsigned char
然后,我可以使用unsigned char*对内容的这种解释std::string作为访问和更改[0, 255]范围内字节值的一种方式,以一种明确定义和可移植的方式,而不管其char自身的符号性如何。
这应该可以解决由潜在签名引起的任何问题char。
我的假设和结论正确吗?
此外,unsigned char*相同位模式(即11111111b或10101010b)的解释是否保证在所有实现中都相同?换句话说,标准是否保证“通过眼睛看unsigned char”,相同的位模式总是导致相同的数值(假设一个字节中的位数相同)?
因此,我可以安全地(即,没有任何未定义或实现定义的行为)std::string用于在 C++11 中存储和操作二进制数据吗?