如何创建行为完全类似的类:std::cout
& std::cerr
。
我正在编写一个迷你操作系统,这是一个要求,有这些模块在那里。
代码将如下所示:
myNewCoutClass myCout; // create cout behavioral class
myNewCerrClass myCerr; // create cerr behavioral class
myCout << someString << endl; // prints the string
myCerr << someString << endl; // prints the string as error
发布于 2016-03-09 05:47:29
首先,不做,除非您非常清楚自己在做什么,并且愿意承担所涉及的所有风险。这只是一个例子,说明了如何将另一个流绑定到stdout
,实际上创建了第二个cout
,作为一个思想实验。那就是说,我们开始吧。
如果您想为stdout
创建另一个流,则必须仔细查看编译器的深而暗的内部,并了解它是如何定义cout
、cerr
和/或clog
的。这将位于依赖于编译器的位置,很可能不是您所期望的位置;例如,在Visual的旧版本上,您必须查看crt\src
文件夹中的几个文件:
// Visual Studio 2010 implementation of std::cout.
// Irrelevant parts omitted.
// cout.cpp
__PURE_APPDOMAIN_GLOBAL static filebuf fout(_cpp_stdout);
#if defined(_M_CEE_PURE)
__PURE_APPDOMAIN_GLOBAL extern ostream cout(&fout);
#else
__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 ostream cout(&fout);
#endif
struct _Init_cout
{
__CLR_OR_THIS_CALL _Init_cout()
{
_Ptr_cout = &cout;
if (_Ptr_cin != 0)
_Ptr_cin->tie(_Ptr_cout);
if (_Ptr_cerr != 0)
_Ptr_cerr->tie(_Ptr_cout);
if (_Ptr_clog != 0)
_Ptr_clog->tie(_Ptr_cout);
}
};
__PURE_APPDOMAIN_GLOBAL static _Init_cout init_cout;
// stdio.h
#define _INTERNAL_BUFSIZ 4096
// ...
#define _IOB_ENTRIES 20
// ...
#ifndef _STDSTREAM_DEFINED
#define stdin (&__iob_func()[0])
#define stdout (&__iob_func()[1])
#define stderr (&__iob_func()[2])
#define _STDSTREAM_DEFINED
#endif /* _STDSTREAM_DEFINED */
// _file.c
char _bufin[_INTERNAL_BUFSIZ];
FILE _iob[_IOB_ENTRIES] = {
/* _ptr, _cnt, _base, _flag, _file, _charbuf, _bufsiz */
/* stdin (_iob[0]) */
{ _bufin, 0, _bufin, _IOREAD | _IOYOURBUF, 0, 0, _INTERNAL_BUFSIZ },
/* stdout (_iob[1]) */
{ NULL, 0, NULL, _IOWRT, 1, 0, 0 },
/* stderr (_iob[3]) */
{ NULL, 0, NULL, _IOWRT, 2, 0, 0 },
};
_CRTIMP FILE * __cdecl __iob_func(void)
{
return _iob;
}
// `__PURE_APPDOMAIN_GLOBAL` is an internal macro that can generally be ignored.
// `_CRTIMP` is an internal macro that can generally be ignored.
// `_CRTDATA2` is an internal macro that can generally be ignored.
// `__CLR_OR_THIS_CALL` is a calling convention macro that expands to either
// `__clrcall` or `__thiscall`.
由此,我们可以为stdout
派生我们自己的流,尽管它将依赖于编译器。
// Visual Studio 2010 user-created char16_t cout.
// Note that in VStudio 2010, char16_t is actually a typedef for unsigned short.
#include <iostream>
#include <fstream>
#include <string>
#include <codecvt>
#define _cpp_stdout (&(__iob_func())[1])
typedef std::basic_filebuf<char16_t, std::char_traits<char16_t>> filebuf_c16;
typedef std::basic_ostream<char16_t, std::char_traits<char16_t>> ostream_c16;
int main() {
filebuf_c16 f16out(_cpp_stdout);
ostream_c16 c16out(&f16out);
// It really should be tied to the other stdin/stdout/stderr streams,
// but this is a simple program where it won't be a problem.
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
std::string u8tmp = "Hello from char16_t!";
std::u16string u16str = converter.from_bytes(u8tmp);
c16out << u16str << std::endl;
}
结果..。
Hello from char16_t!
如果您想要绑定第二个标准ostream
(a.k.a )。( basic_ostream<char, char_traits<char>>
)对于stdout
,您可以使用类似的东西。注意,由于fout
是static
,所以您需要创建自己的filebuf
。还请注意,这只是自找麻烦,但这不是重点;只是要小心数据竞赛,或任何类似的事情。
请注意,尽管您可以这样做,除非您非常清楚自己正在做什么,否则您愿意对任何出错的事情负责,并且愿意花费足够的时间深入您的编译器的库和/或代码,以了解它如何准确地实现stdout
和默认字符串,但您不应该这么做。
还请注意,您的代码将与编译器紧密耦合,并且很有可能会出现相同编译器的未来版本破坏它的可能性。例如,据我所知,由于CRT的更改,这段代码不会使用Visual 2015进行编译(具体来说,我认为这是因为对FILE
的更改,但我没有研究它)。
发布于 2015-10-10 09:43:12
这些对象是std::ostream
的,您可以创建自己的std::ostream
。确切地说,它的工作方式完全取决于您尚未指定的数据接收器,但std::ostringstream
将足以让您开始测试使用它的代码。
但是,如果你真的想要重新发明std::cout
,不要。它的数据接收器是神奇的文件句柄stdout,你不能重新创建它,因为它是由操作系统提供的。您可以创建一个从std::ostream
中窃取缓冲区的std::cout
,但这有什么意义呢?
https://stackoverflow.com/questions/33052540
复制相似问题