std::具有二进制数据的字符串流流运算符
std::stringstream stream operators with binary data
我正在为一个类编写一些测试用例,该类可能会从std::istream
读取并写入std::ostream
。作为测试过程的一部分,我想手动创建一个测试文件数据块,将其包装在std::stringstream
中,然后将其传递给我的类进行处理。
我觉得我目前的解决方案缺乏,尽管它确实有效。我真的不喜欢将那些原始写入调用与reinterpret_cast
一起使用。
std::stringstream file;
uint32_t version = 1;
uint32_t dataSize = 10;
uint32_t recordCount = 3;
file.write(reinterpret_cast<char*>(&version), sizeof(version));
file.write(reinterpret_cast<char*>(&dataSize), sizeof(dataSize));
file.write(reinterpret_cast<char*>(&recordCount), sizeof(recordCount));
myclass.read(file)
有没有办法使用流运算符以二进制形式写入此数据?我希望有更多类似于以下内容的内容。
std::stringstream file;
uint32_t version = 1;
uint32_t dataSize = 0;
uint32_t recordCount = 3;
file << version << dataSize << recordCount;
myclass.read(file);
如果我走这条路,提取一个数字会产生103
这在 ascii 上下文中是预期的,但我显然试图避免以这种方式序列化我的数据。
您的代码存在问题:当您使用 reinterpret_cast
,你实际上并不知道你在写什么到流,所以你不知道你在测试什么。 如果你想要测试您的代码如何对字节流做出反应二进制格式,您可以轻松初始化 std::istringstream
具有任意字节流:
char bytes[] = { /*...*/ };
std::istringstream( std::string( std::begin( bytes ), std::end( bytes ) ) );
(如果您没有 C++11,您可以轻松编写自己的begin
和end
.(
通过这种方式,您将确切地知道字节是什么,而不是取决于实现如何表示任何特定类型。
或者:如果您正在读取和写入二进制数据,则可能想要定义执行此操作的类,使用 >>
和 <<
。此类类与std::istream
和 std::ostream
,但逻辑上可以使用std::ios_base
为常规错误报告和接口到std::streambuf
。 然后,该类将具有成员类似于以下内容:
namespace {
class ByteGetter
{
public:
explicit ByteGetter( ixdrstream& stream )
: mySentry( stream )
, myStream( stream )
, mySB( stream->rdbuf() )
, myIsFirst( true )
{
if ( ! mySentry ) {
mySB = NULL ;
}
}
std::uint8_t get()
{
int result = 0 ;
if ( mySB != NULL ) {
result = mySB->sgetc() ;
if ( result == EOF ) {
result = 0 ;
myStream.setstate( myIsFirst
? std::ios::failbit | std::ios::eofbit
: std::ios::failbit | std::ios::eofbit | std::ios::badbit ) ;
}
}
myIsFirst = false ;
return result ;
}
private:
ixdrstream::sentry mySentry ;
ixdrstream& myStream ;
std::streambuf* mySB ;
bool myIsFirst ;
} ;
}
ixdrstream&
ixdrstream::operator>>( std::uint32_t& dest )
{
ByteGetter source( *this ) ;
std::uint32_t tmp = source.get() << 24 ;
tmp |= source.get() << 16 ;
tmp |= source.get() << 8 ;
tmp |= source.get() ;
if ( *this ) {
dest = tmp ;
}
return *this ;
}
(为了获得最大的可移植性,您可能不会避免 uint8_t
和uint32_t
. 在此级别,编写代码时无需知道类型的确切大小有点困难,因此,如果您确定,您将永远不必移植到异国情调可能未定义的系统,可能值得保存你自己做了额外的工作。
您可以为 ostream 声明运算符<<
(因此不仅是字符串流,还包括文件流(。 类似以下内容的内容可能有效(未经测试(,但您可能会遇到类型 (uint32_t( 的问题:
std::ostream& operator<<(std::ostream& stream, uint32_t value)
{
stream.write(reinterpret_cast<char*>(&value), sizeof(value));
return stream;
}
std::stringstream file;
file << version << dataSize << recordCount;
编辑:
由于类型值 has,因此已定义<<
运算符。 一种替代方法是声明一个新的运算符<=
:
std::ostream& operator<=(std::ostream& stream, uint32_t value);
file <= version <= dataSize <= recordCount;
两个运算符都以从左到右的方式运行,因此这可能有效,但可能不是最好的解决方案。
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 为什么字符串比较的 == 运算符相对于任一字符串长度线性时间(似乎)?
- 是否可以将带有字符串化运算符的宏转换为 constexpr?
- 在 c++ 中对字符串进行操作的关系运算符无法按预期工作
- Qt PL/SQL - 赋值运算符 - 字符串缓冲区太小
- 重载 std::字符串运算符+ 用于打印枚举名称
- <<运算符优先级与字符串比较
- C++ |<<运算符重载和打印字符串
- ">"运算符和"<"运算符如何进行字符串比较?
- C++重载字符串 [] 运算符以返回字符串和
- C++STL字符串运算符+关联性
- 字符串运算符,如std::String
- 字符串运算符的求值顺序未指定
- 重载字符串运算符+
- c++字符串+=运算符内存结果
- 字符串运算符 += 有时在 string::resize() 之后不起作用
- 字符串::运算符+=出现问题
- 从 C++ 到 PHP 的'+'字符串运算符
- 字符串::at和字符串::运算符[]之间的区别是什么
- 字符串运算符重载我真的不明白