我可以安全地在C++ 11中使用std :: string作为二进制数据吗?

Joh*_*and 19 c++ stdstring c++11

互联网上有几篇帖子暗示你应该使用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,这基本上是一个typedef std::basic_string<char>.

使用std::string二进制数据的唯一潜在剩余问题(我可以看到)是std::string使用char(可以签名).

char,signed char和,unsigned char是三种不同的类型,char可以是未签名或签名.

因此,当11111111bstd::string:operator[]char 返回实际字节值,并且您想要检查其值时,其值可以是255(如果char是无符号的),也可能是"负面的"(如果char已签名,则取决于您的数字表示).

类似地,如果要将实际字节值显式附加11111111b到a std::string,则只需附加(char) (255)可能是实现定义的(甚至引发信号),如果char已签名且intto char会话导致溢出.

那么,有没有一种安全的解决方法,这又使std::string二元安全?

§3.10/ 15指出:

如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:

  • [...]
  • 与对象的动态类型对应的有符号或无符号类型的类型,
  • [...]
  • char或unsigned char类型.

如果我理解正确的话,似乎允许使用unsigned char*指针访问和操作a的内容std::string并使其也定义良好.它只是重新解释的位模式作为unsigned char,而没有任何变化或信息丢失,即因为在所有位后者char,signed char以及unsigned char必须使用的值表示.

然后,我可以使用这种unsigned char*内容的解释std::string作为一种手段[0, 255],以一种定义良好且可移植的方式访问和更改该范围内的字节值,而不管其char自身的有效性.

这应该可以解决潜在签名产生的任何问题char.

我的假设和结论是否正确?

此外,在所有实现unsigned char*中,相同位模式(即11111111b10101010b)的解释是否保证相同?换句话说,标准保证"通过眼睛看unsigned char",相同的位模式总是会导致相同的数值(假设一个字节中的位数是相同的)?

我可以安全地(即,没有任何未定义或实现定义的行为)std::string用于在C++ 11中存储和操作二进制数据吗?

Die*_*ühl 18

转换static_cast<char>(uc),其中uc是类型是unsigned char始终是有效的:根据3.9.1 [basic.fundamental]的表示char,signed char以及unsigned char与相同的char是相同的两个其它类型之一:

声明为字符(char)的对象应足够大,以存储实现的基本字符集的任何成员.如果此组中的字符存储在字符对象中,则该字符对象的整数值等于该字符的单个字符文字形式的值.实现定义char对象是否可以保存负值.字符可以显式声明为unsigned或signed.Plain char,signed char和unsigned char是三种不同的类型,统称为窄字符类型.char,signed char和unsigned char占用相同的存储空间并具有相同的对齐要求(3.11); 也就是说,它们具有相同的对象表示.对于窄字符类型,对象表示的所有位都参与值表示.对于无符号窄字符类型,值表示的所有可能位模式表示数字.这些要求不适用于其他类型.在任何特定实现中,普通char对象可以采用与signed char或unsigned char相同的值; 哪一个是实现定义的.

的范围之外的变换值unsigned charchar意愿,当然,是有问题的,并且可能导致未定义的行为.也就是说,只要你不尝试将有趣的值存储到std::string你就可以了.关于位模式,您可以依靠该n位转换为2 n.在std::string仔细处理时,存储二进制数据应该没有问题.

也就是说,我不买入你的前提:处理二进制数据主要需要处理最好使用unsigned值操作的字节.在没有明确处理的情况下,你需要转换char*unsigned char*创建方便的错误,同时搞乱char意外使用的少数情况将是沉默的!也就是说,处理unsigned char将防止错误.我也不会购买你得到所有那些好的字符串函数的前提:首先,你通常最好不要使用算法,但二进制数据也不是字符串数据.总结:建议std::vector<unsigned char>不仅仅是凭空而来!故意避免在设计中难以找到陷阱!

唯一有利于使用的温和合理的论据char可能是关于字符串文字的论点,但即便如此也没有用C++ 11引入的用户定义的字符串文字:

#include <cstddef>
unsigned char const* operator""_u (char const* s, size_t) 
{
    return reinterpret_cast<unsigned char const*>(s);
}

unsigned char const* hello = "hello"_u;
Run Code Online (Sandbox Code Playgroud)

  • @ JohnCaC2:1."signed char"和"unsigned char"的表示可以在不改变位的情况下相互映射.结果是正的`signed char`值将与`unsigned char`值具有相同的值; 如何指定负值转换为`unsigned char`或反过来但是位模式仍然没有改变.那就是将`signed char`转换为`unsigned char`,然后返回标识函数(同样反过来).2.`reinterpret_cast <char*>(...)`.关键是,编译器捕获了所需的位置. (3认同)