互联网上有几篇帖子建议您使用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>
的typedef。
使用std::string
二进制数据的唯一潜在问题(我可以看到)是std::string
使用char
(可以签名)。
char
,signed char
和unsigned char
有三种不同类型,char
可以是无符号或已签名。
因此,当11111111b
的实际字节值作为char返回时,如果要检查其值,则其值可以是std::string:operator[]
(如果{{1} }}是无符号的)或者它可能是“负面的”(如果255
已签名,具体取决于你的数字代表)。
同样,如果要将实际字节值char
显式附加到char
,只需添加11111111b
可能是实现定义的(甚至可以引发信号){} { 1}}已签名,std::string
到(char) (255)
会话导致溢出。
那么,是否有一种安全的方法可以使char
二进制安全?
§3.10/ 15声明:
如果某个程序试图通过以下某种类型之外的 glvalue 访问对象的存储值,则行为未定义:
- [...]
- 与对象的动态类型对应的有符号或无符号类型的类型
- [...]
- char或unsigned char类型。
如果我理解正确的话,似乎允许使用int
指针来访问和操作char
的内容,并使明确定义。它只是重新解释位模式为std::string
,没有任何变化或信息丢失,后者即因为unsigned char*
,std::string
和{中的所有位{1}}必须用于值表示。
然后我可以使用unsigned char
对char
内容的解释,作为一种以明确定义和可移植的方式访问和更改signed char
范围内的字节值的方法,无论unsigned char
本身的签名如何。
这可以解决因可能签名的unsigned char*
而引起的任何问题。
我的假设和结论是否正确?
此外,对于所有实现,相同位模式(即std::string
或[0, 255]
)的char
解释是否保证相同?换句话说,标准是否保证“通过char
的眼睛看”,相同的位模式总是会导致相同的数值(假设一个字节中的位数相同)?
我可以安全地(即没有任何未定义或实现定义的行为)使用unsigned char*
来存储和操作C ++ 11中的二进制数据吗?
答案 0 :(得分:19)
其中static_cast<char>(uc)
类型为uc
的转化unsigned char
始终有效:根据3.9.1 [basic.fundamental] char
的表示,{{ 1}},signed char
与unsigned char
相同,与其他两种类型相同:
声明为字符(char)的对象应足够大,以存储实现的基本字符集的任何成员。如果此组中的字符存储在字符对象中,则该字符对象的整数值等于该字符的单个字符文字形式的值。实现定义char对象是否可以保存负值。字符可以显式声明为unsigned或signed。 Plain char,signed char和unsigned char是三种不同的类型,统称为窄字符类型。 char,signed char和unsigned char占用相同的存储空间并具有相同的对齐要求(3.11);也就是说,它们具有相同的对象表示。对于窄字符类型,对象表示的所有位都参与值表示。对于无符号窄字符类型,值表示的所有可能位模式表示数字。这些要求不适用于其他类型。在任何特定实现中,普通char对象可以采用相同的方式 值作为signed char或unsigned char;哪一个是实现定义的。
将char
范围之外的值转换为unsigned char
当然会产生问题,并可能导致未定义的行为。也就是说,只要您不尝试将有趣的值存储到char
中,您就可以了。关于位模式,您可以依靠std::string
位转换为2 n
。在仔细处理时,在n
中存储二进制数据应该没有问题。
那就是说,我不会买入你的前提:处理二进制数据主要需要处理使用std::string
值最佳操作的字节。您需要在unsigned
和char*
之间进行转换的少数情况会在未明确处理的情况下创建方便的错误,同时意外地使用unsigned char*
将会保持沉默!也就是说,处理char
可以防止错误。我也不会购买你得到所有那些好的字符串函数的前提:首先,你通常最好不要使用算法,但二进制数据不字符串数据。总结:对unsigned char
的建议不仅仅是凭空而来!故意避免难以在设计中找到陷阱!
支持使用std::vector<unsigned char>
的唯一温和合理的论点可能是关于字符串文字的论点,但即便如此也没有用C ++ 11中引入的用户定义的字符串文字:
char
答案 1 :(得分:1)
是的,您的假设是正确的。 将二进制数据存储为std :: string中的unsigned char序列。
答案 2 :(得分:-1)
我在使用std :: string处理Microsoft Visual Studio中的二进制数据时遇到了麻烦。我已经看到字符串被莫名其妙地截断了,所以无论标准文件说什么,我都不会这样做。