检查 C++ 字符流是否连接到终端/控制台/tty 的函数。
理想情况下,我们将使用位于 C++ stdio 流(cin、cout、cerr 或 clog)的流缓冲区之下的文件描述符。但是,无法检索底层文件描述符。因此,我们使用的事实是,在程序启动时,stdio 流缓冲区连接到程序的标准输入和输出。
此功能仅在以下情况下有效:
启动 C++ stdio 流的流缓冲区不得更改。因为启动 C++ stdio 流的流缓冲区的地址被用作标识符。例如,通过删除它们,然后分配一个新的流缓冲区,该缓冲区与启动 C++ stdio 流的这些流缓冲区之一具有相同的地址。
程序启动后,程序的 stdio 不得改变。因为 stdio 流缓冲区的 TTY 状态是在程序启动时存储的。例如,如果在启动时 std. out 连接到一个终端,然后它被程序外部的东西重定向到管道或文件。[您可以在运行时检索它们,而不是在启动时存储 TTY 状态,但是您必须确保您的程序(以及它使用的所有库)不会更改 stdio 文件描述符(0、1 和 2) . 请记住,stdio 流缓冲区很可能使用其他(重复)文件描述符。]
代码:
#include <iostream>
extern "C" {
#ifdef _WIN32
# include <io.h> // for: _isatty()
#else
# include <unistd.h> // for: isatty()
#endif
}
// Stdio file descriptors.
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
# define STDOUT_FILENO 1
# define STDERR_FILENO 2
#endif
// Store start-up addresses of C++ stdio stream buffers as identifiers.
// These addresses differ per process and must be statically linked in.
// Assume that the stream buffers at these stored addresses
// are always connected to their underlaying stdio files.
static const streambuf* const StdioBufs[] = {
std::cin.rdbuf(), std::cout.rdbuf(), std::cerr.rdbuf(), std::clog.rdbuf()
};
static const wstreambuf* const StdioWBufs[sizeof(StdioBufs)/sizeof(StdioBufs[0])] = {
std::wcin.rdbuf(), std::wcout.rdbuf(), std::wcerr.rdbuf(), std::wclog.rdbuf()
};
// Store start-up terminal/TTY statuses of C++ stdio stream buffers.
// These statuses differ per process and must be statically linked in.
// Assume that the statuses don't change during the process life-time.
static const bool StdioTtys[sizeof(StdioBufs)/sizeof(StdioBufs[0])] = {
#ifdef _WIN32
_isatty(STDIN_FILENO), _isatty(STDOUT_FILENO), _isatty(STDERR_FILENO), _isatty(STDERR_FILENO)
#else
isatty(STDIN_FILENO), isatty(STDOUT_FILENO), isatty(STDERR_FILENO), isatty(STDERR_FILENO)
#endif
};
// Is a Terminal/Console/TTY connected to the C++ stream?
// Use on C++ stdio chararacter streams: cin, cout, cerr and clog.
bool isTTY(const ios& strm)
{
for(unsigned int i = 0; i < sizeof(StdioBufs)/sizeof(StdioBufs[0]); ++i) {
if(strm.rdbuf() == StdioBufs[i])
return StdioTtys[i];
}
return false;
}
// Is a Terminal/Console/TTY connected to the C++ stream?
// Use on C++ stdio wide-chararacter streams: wcin, wcout, wcerr and wclog.
bool isTTY(const wios& strm)
{
for(unsigned int i = 0; i < sizeof(StdioWBufs)/sizeof(StdioWBufs[0]); ++i) {
if(strm.rdbuf() == StdioWBufs[i])
return StdioTtys[i];
}
return false;
}
注意:我只在 Linux 上测试过。