首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何创建自己的“cout”和“cerr”类

如何创建自己的“cout”和“cerr”类
EN

Stack Overflow用户
提问于 2015-10-10 09:40:44
回答 2查看 2.9K关注 0票数 4

如何创建行为完全类似的类:std::cout & std::cerr

我正在编写一个迷你操作系统,这是一个要求,有这些模块在那里。

代码将如下所示:

代码语言:javascript
运行
复制
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
EN

回答 2

Stack Overflow用户

发布于 2016-03-09 05:47:29

首先,不做,除非您非常清楚自己在做什么,并且愿意承担所涉及的所有风险。这只是一个例子,说明了如何将另一个流绑定到stdout,实际上创建了第二个cout,作为一个思想实验。那就是说,我们开始吧。

如果您想为stdout创建另一个流,则必须仔细查看编译器的深而暗的内部,并了解它是如何定义coutcerr和/或clog的。这将位于依赖于编译器的位置,很可能不是您所期望的位置;例如,在Visual的旧版本上,您必须查看crt\src文件夹中的几个文件:

代码语言:javascript
运行
复制
// 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派生我们自己的流,尽管它将依赖于编译器。

代码语言:javascript
运行
复制
// 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;
}

结果..。

代码语言:javascript
运行
复制
Hello from char16_t!

如果您想要绑定第二个标准ostream (a.k.a )。( basic_ostream<char, char_traits<char>>)对于stdout,您可以使用类似的东西。注意,由于foutstatic,所以您需要创建自己的filebuf。还请注意,这只是自找麻烦,但这不是重点;只是要小心数据竞赛,或任何类似的事情。

请注意,尽管您可以这样做,除非您非常清楚自己正在做什么,否则您愿意对任何出错的事情负责,并且愿意花费足够的时间深入您的编译器的库和/或代码,以了解它如何准确地实现stdout和默认字符串,但您不应该这么做。

还请注意,您的代码将与编译器紧密耦合,并且很有可能会出现相同编译器的未来版本破坏它的可能性。例如,据我所知,由于CRT的更改,这段代码不会使用Visual 2015进行编译(具体来说,我认为这是因为对FILE的更改,但我没有研究它)。

票数 2
EN

Stack Overflow用户

发布于 2015-10-10 09:43:12

这些对象是std::ostream的,您可以创建自己的std::ostream。确切地说,它的工作方式完全取决于您尚未指定的数据接收器,但std::ostringstream将足以让您开始测试使用它的代码。

但是,如果你真的想要重新发明std::cout,不要。它的数据接收器是神奇的文件句柄stdout,你不能重新创建它,因为它是由操作系统提供的。您可以创建一个从std::ostream中窃取缓冲区的std::cout,但这有什么意义呢?

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33052540

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档