C++中是否有二进制内存流
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1559254/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Are there binary memory streams in C++
提问by FireAphis
I usually use stringstream
to write into in-memory string. Is there a way to write to a char buffer in binary mode? Consider the following code:
我通常stringstream
用来写入内存中的字符串。有没有办法以二进制模式写入字符缓冲区?考虑以下代码:
stringstream s;
s << 1 << 2 << 3;
const char* ch = s.str().c_str();
The memory at ch
will look like this: 0x313233 - the ASCII codes of the characters 1, 2 and 3. I'm looking for a way to write the binary values themselves. That is, I want 0x010203 in the memory. The problem is that I want to be able to write a function
内存ch
将如下所示:0x313233 - 字符 1、2 和 3 的 ASCII 代码。我正在寻找一种方法来编写二进制值本身。也就是说,我想要内存中的 0x010203。问题是我希望能够写一个函数
void f(ostream& os)
{
os << 1 << 2 << 3;
}
And decide outside what kind of stream to use. Something like this:
并在外部决定使用哪种流。像这样的东西:
mycharstream c;
c << 1 << 2 << 3; // c.data == 0x313233;
mybinstream b;
b << 1 << 2 << 3; // b.data == 0x010203;
Any ideas?
有任何想法吗?
回答by KeithB
To read and write binary data to streams, including stringstreams, use the read() and write() member functions. So
要将二进制数据读取和写入流,包括字符串流,请使用 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";
This gives 0x4030201
on my system.
这给0x4030201
了我的系统。
Edit: To make this work transparently with the insertion and extraction operators (<< and >>), your best bet it to create a derived streambuf that does the right thing, and pass that to whatever streams you want to use.
编辑:为了使用插入和提取运算符(<< 和 >>)使这项工作透明化,最好创建一个派生的流缓冲,它可以做正确的事情,并将其传递给您想要使用的任何流。
回答by Samuel Powell
You can do this sort of thing with templates. 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));
}
It could use some cleanup, but it's functional. 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);
回答by Jean Daniel Pauget
overloading some unusual operators works rather well. Here below I choosed to overload <=because it has the same left-to-right associativity as <<and has somehow a close look-and-feel ...
重载一些不寻常的运算符效果很好。在下面,我选择重载<=因为它具有与<<相同的从左到右关联性,并且在某种程度上具有接近的外观......
#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;
}
There are several drawbacks :
有几个缺点:
the new meaning of <=may confuse readers or lead to unexpected results :
cout <= 31 <= 32;
won't give the same result as
cout <= (31 <= 32);
the endianess isn't clearly mentionned at reading the code, as illustrated in the above example.
it cannot mix simply with <<because it doesn't belong to the same group of precedence. I usually use parenthesis to clarify such as :
( cout <= htonl(a) <= htonl(b) ) << endl;
<=的新含义可能会混淆读者或导致意想不到的结果:
cout <= 31 <= 32;
不会给出相同的结果
cout <= (31 <= 32);
如上例所示,在阅读代码时没有明确提及字节序。
它不能简单地与<<混合,因为它不属于同一组优先级。我通常使用括号来澄清,例如:
( cout <= htonl(a) <= htonl(b) ) << endl;
回答by kamikaze
For this use case I implemented myself a "raw shift operator":
对于这个用例,我自己实现了一个“原始移位运算符”:
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;
}
Put it somewhere convenient and use it like this:
把它放在方便的地方并像这样使用它:
std::cout <= 1337 <= 1337ULL <= 1337. <= 1337.f;
Advantages:
好处:
- chainable
- automatic
sizeof()
- takes arrays and struct/class instances, too
- 可链接的
- 自动的
sizeof()
- 也接受数组和结构/类实例
Disadvantages:
缺点:
- unsafe for non-POD objects: leaks pointers and padding
- output is platform specific: padding, endianess, integer types
- 对非 POD 对象不安全:泄漏指针和填充
- 输出是特定于平台的:填充、字节序、整数类型
回答by Luká? Lalinsky
Well, just use characters, not integers.
好吧,只使用字符,而不是整数。
s << char(1) << char(2) << char(3);