C ++中是否存在二进制内存流

时间:2009-10-13 10:01:33

标签: c++ iostream

我通常使用stringstream写入内存中的字符串。有没有办法在二进制模式下写入char缓冲区?请考虑以下代码:

stringstream s;
s << 1 << 2 << 3;
const char* ch = s.str().c_str();

ch处的内存将如下所示:0x313233 - 字符1,2和3的ASCII代码。我正在寻找一种自己编写二进制值的方法。也就是说,我想在内存中使用0x010203。问题是我希望能够编写一个函数

void f(ostream& os)
{
    os << 1 << 2 << 3;
}

并决定使用哪种流。像这样:

mycharstream c;
c << 1 << 2 << 3; // c.data == 0x313233;
mybinstream b;
b << 1 << 2 << 3; // b.data == 0x010203;

有什么想法吗?

5 个答案:

答案 0 :(得分:34)

要读取和写入包含字符串流的流的二进制数据,请使用read()和write()成员函数。所以

unsigned char a(1), b(2), c(3), d(4);
std::stringstream s;
s.write(reinterpret_cast<const char*>(&a), sizeof(unsigned char));
s.write(reinterpret_cast<const char*>(&b), sizeof(unsigned char));
s.write(reinterpret_cast<const char*>(&c), sizeof(unsigned char));
s.write(reinterpret_cast<const char*>(&d), sizeof(unsigned char));

s.read(reinterpret_cast<char*>(&v), sizeof(unsigned int)); 
std::cout << std::hex << v << "\n";

这会在我的系统上提供0x4030201

编辑: 为了使用插入和提取操作符(&lt;&lt;&gt;&gt;)透明地工作,最好用它来创建一个做正确事情的派生streambuf,并将其传递给你想要使用的任何流。

答案 1 :(得分:4)

好吧,只使用字符,而不是整数。

s << char(1) << char(2) << char(3);

答案 2 :(得分:3)

重载一些不寻常的运算符效果相当好。在下面我选择重载&lt; = ,因为它具有与&lt;&lt; 相同的从左到右的关联性,并且具有某种近似的外观。 ..

#include <iostream>
#include <stdint.h>
#include <arpa/inet.h>

using namespace std;

ostream & operator<= (ostream& cout, string const& s) {
    return cout.write (s.c_str(), s.size());
}
ostream & operator<= (ostream& cout, const char *s) {
    return cout << s;
}
ostream & operator<= (ostream&, int16_t const& i) {
    return cout.write ((const char *)&i, 2);
}
ostream & operator<= (ostream&, int32_t const& i) {
    return cout.write ((const char *)&i, 4);
}
ostream & operator<= (ostream&, uint16_t const& i) {
    return cout.write ((const char *)&i, 2);
}
ostream & operator<= (ostream&, uint32_t const& i) {
    return cout.write ((const char *)&i, 4);
}

int main() {
    string s("some binary data follow : ");

    cout <= s <= " (machine ordered) : " <= (uint32_t)0x31323334 <= "\n"
         <= s <= " (network ordered) : " <= htonl(0x31323334) ;
    cout << endl;

    return 0;
}

有几个缺点:

  • &lt; = 的新含义可能会使读者感到困惑或导致意外结果:

    cout <= 31 <= 32;
    

    不会给出与

    相同的结果
    cout <= (31 <= 32);
    
  • 在阅读代码时没有明确提到结尾,如 如上例所示。

  • 它不能与&lt;&lt; 简单混用,因为它不属于 同一组优先权。我通常用括号来澄清这种情况 as:

    ( cout <= htonl(a) <= htonl(b) ) << endl;
    

答案 3 :(得分:3)

您可以使用模板执行此类操作。 E.g:

//struct to hold the value:
template<typename T> struct bits_t { T t; }; //no constructor necessary
//functions to infer type, construct bits_t with a member initialization list
//use a reference to avoid copying. The non-const version lets us extract too
template<typename T> bits_t<T&> bits(T &t) { return bits_t<T&>{t}; }
template<typename T> bits_t<const T&> bits(const T& t) { return bits_t<const T&>{t}; }
//insertion operator to call ::write() on whatever type of stream
template<typename S, typename T>
S& operator<<(S &s, bits_t<T> b) {
    return s.write((char*)&b.t, sizeof(T));
}
//extraction operator to call ::read(), require a non-const reference here
template<typename S, typename T>
S& operator>>(S& s, bits_t<T&> b) {
    return s.read((char*)&b.t, sizeof(T));
}

它可以使用一些清理,但它的功能。 E.g:

//writing
std::ofstream f = /*open a file*/;
int a = 5, b = -1, c = 123456;
f << bits(a) << bits(b) << bits(c);

//reading
std::ifstream f2 = /*open a file*/;
int a, b, c;
f >> bits(a) >> bits(b) >> bits(c);

答案 4 :(得分:2)

对于这个用例,我实现了一个&#34;原始移位运算符&#34;:

template <typename T, class... StreamArgs>
inline std::basic_ostream<StreamArgs...> &
operator <= (std::basic_ostream<StreamArgs...> & out, T const & data) {
        out.write(reinterpret_cast<char const *>(&data), sizeof(T));
        return out;
}

把它放在方便的地方并按照这样使用:

std::cout <= 1337 <= 1337ULL <= 1337. <= 1337.f;

优点:

  • 环连接的
  • 自动sizeof()
  • 也采用数组和结构/类实例

缺点:

  • 对非POD对象不安全:泄漏指针和填充
  • 输出是特定于平台的:padding,endianess,integer types