【问题标题】:How to check if stdout has been redirected to NUL on Windows (a.k.a. /dev/null on Linux)?如何检查标准输出是否已在 Windows 上重定向到 NUL(在 Linux 上也称为 /dev/null)?
【发布时间】:2014-01-30 22:24:18
【问题描述】:

如何检查我的程序的stdout 是否已重定向到NUL?
这样我就可以避免输出数据,因为它没有意义。

我主要在 Windows 上需要这个,但如果你有一个 Linux 解决方案,它可能在未来对其他人有帮助,所以也欢迎发布。

【问题讨论】:

  • 为什么需要这个?您是否担心输出大量数据的性能开销?如果它对你来说真的那么重要,我建议实现一个命令行选项,使调用者可以指示你的程序不执行输出。
  • @Ruud:是的,性能开销。我不想添加额外的选项,除非它们确实是必要的,如果我能做到这一点,那么它们就不是了。只是一种偏好。
  • 注意:重定向通常由cmd > nul 使用命令处理器或脚本/批处理文件调用。对自称为 Windows 的操作系统提出这样的文本考虑似乎不寻常,但合法? :-)

标签: c winapi visual-c++ stdout


【解决方案1】:

我自己想通了。很烦人。

#include <Windows.h>
#include <io.h>
#pragma comment(lib, "ntdll.lib")  // can instead use GetProcAddress (below)
extern "C" NTSTATUS __stdcall NtQueryVolumeInformationFile(
    HANDLE FileHandle, struct _IO_STATUS_BLOCK *IoStatusBlock,
    void *FsInformation, unsigned long Length,
    enum _FSINFOCLASS FsInformationClass);
bool isdevnull(FILE *file)
{
    struct FILE_FS_DEVICE_INFORMATION
    { unsigned long DeviceType, Characteristics; } fsinfo;
    struct { void *info, *status; } iosb;
    typedef NTSTATUS (__stdcall *PNTQIF)(
        HANDLE FileHandle, struct _IO_STATUS_BLOCK *IoStatusBlock,
        void *FsInformation, unsigned long Length,
        enum _FSINFOCLASS FsInformationClass);
    PNTQIF const ntqif =
        true  // True if you have ntdll.lib, false otherwise
        ? NtQueryVolumeInformationFile
        : (PNTQIF) GetProcAddress(
            GetModuleHandle(TEXT("ntdll.dll")),
            "NtQueryVolumeInformationFile");
    return ntqif(
        (HANDLE) _get_osfhandle(_fileno(stdout)),
        (struct _IO_STATUS_BLOCK *)&iosb,
        &fsinfo, sizeof(fsinfo),
        (enum _FSINFOCLASS)4
    ) == 0 && fsinfo.DeviceType == 0x00000015 /*FILE_DEVICE_NULL*/;
}
int main()
{
    bool b = isdevnull(stdout);
}

【讨论】:

    【解决方案2】:

    可能还有其他方法可以做到这一点(如果我忽略了它的适当功能,那也不足为奇),但这是一种方法:

    enum
    {
        Output_Console,
        Output_File,
        Output_NUL,
    };
    
    bool GetOutputHandleType(int* piType)
    {
        HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
        if (h)
        {
            BY_HANDLE_FILE_INFORMATION fi;
            if (GetFileInformationByHandle(h, &fi))
            {
                *piType = Output_File;
                return true;
            }
            if (GetLastError() == ERROR_INVALID_FUNCTION)
            {
                *piType = Output_NUL;
                return true;
            }
            if (GetLastError() == ERROR_INVALID_HANDLE)
            {
                *piType = Output_Console;
                return true;
            }
        }
        return false;
    }
    

    【讨论】:

    • 哦,聪明,希望它不会破坏其他东西...... +1
    • 对我来说,GetFileInformationByHandle((HANDLE)(_get_osfhandle(_fileno(stderr))), &amp;fi) 返回 0,GetLastErorr() 为 2>NUL 和 2>CON 提供 ERROR_INVALID_FUNCTION=1。但是GetFileInformationByHandleEx(.., FileNameInfo, ..) 为 2>NUL 生成 ERROR_INVALID_PARAMETER=87 !!
    猜你喜欢
    • 1970-01-01
    • 2019-04-07
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 2016-01-20
    • 1970-01-01
    • 2020-02-10
    • 2021-03-30
    相关资源
    最近更新 更多