简体   繁体   中英

Redirect stdout/stderr to null vs2017 c++

I'm trying to upgrade a project from VS2013 to VS2017. I have everything working except for one thing - I'm encountering a crash when printf is called. The crash is as follows:

Unhandled exception at 0x0073910C in exename.exe: An invalid parameter was passed to a function that considers invalid parameters fatal.

exename.exe!_invoke_watson(const wchar_t * expression, const wchar_t * function_name, const wchar_t * file_name, unsigned int line_number, unsigned int reserved) Line 224   C++
exename.exe!_invalid_parameter(const wchar_t * const expression, const wchar_t * const function_name, const wchar_t * const file_name, const unsigned int line_number, const unsigned int reserved) Line 112 C++
exename.exe!_invalid_parameter_noinfo() Line 117 C++
exename.exe!_isatty(int fh) Line 17  C++
exename.exe!__acrt_stdio_begin_temporary_buffering_nolock(_iobuf * public_stream) Line 43    C++
[Inline Frame] exename.exe!__acrt_stdio_temporary_buffering_guard::{ctor}(_iobuf * const stream) Line 399    C++
exename.exe!common_vfprintf::__l2::<lambda>() Line 36    C++
exename.exe!__crt_seh_guarded_call<int>::operator()<void <lambda>(void),int <lambda>(void) &,void <lambda>(void) >(__acrt_lock_stream_and_call::__l2::void <lambda>(void) && setup, common_vfprintf::__l2::int <lambda>(void) & action, __acrt_lock_stream_and_call::__l2::void <lambda>(void) && cleanup) Line 204  C++
exename.exe!__acrt_lock_stream_and_call<int <lambda>(void) >(_iobuf * const stream, common_vfprintf::__l2::int <lambda>(void) && action) Line 256    C++
[Inline Frame] exename.exe!common_vfprintf(const unsigned __int64 options, _iobuf * const stream, const char * const format, __crt_locale_pointers * const locale, char * const arglist) Line 34 C++
exename.exe!__stdio_common_vfprintf(unsigned __int64 options, _iobuf * stream, const char * format, __crt_locale_pointers * locale, char * arglist) Line 58  C++
[Inline Frame] exename.exe!_vfprintf_l(_iobuf * const _Stream, const char * const _Format, __crt_locale_pointers * const) Line 638   C++
exename.exe!printf(const char * const _Format, ...) Line 953 C++

The line looks like this:

printf("simple string goes here");

I've tracked the crash down to these lines:

freopen("/dev/null", "a", stdout);
freopen("/dev/null", "a", stderr);

I can fix it by replacing the lines with this:

freopen("nul", "a", stdout);
freopen("nul", "a", stderr);

I have three questions for those who might know the internals at play here better than me:

  1. This worked in VS2013 but crashes in VS2017 (with no OS change). Why is that?
  2. What is the correct way when targeting Windows to redirect all stdout/stderr output to nothing, such that printf produces no visible output?
  3. Is there a safe cross-platform way to do this? I'm not necessarily looking for something inserted into a standard, but rather something that every major desktop target (windows, linux, mac) works with.

EDIT

It seems there's no portable way to do this, so I just went with the good old platform specific code.

    const char* nullStream = "/dev/null";

#if defined(WIN32)
    nullStream = "nul:";
#endif

    // If we fail to redirect either of these streams, we will crash the nex
    // time we try to use them. So we assert to be sure.
    if (!freopen(nullStream, "a", stdout)) assert(false);
    if (!freopen(nullStream, "a", stderr)) assert(false);

This is one of the places where Windows and Unix have irreconcilable differences and you just have to deal. I'd do it like this:

#ifdef _WIN32
#define NULL_DEVICE "NUL:"
#else
#define NULL_DEVICE "/dev/null"
#endif

and then

freopen(NULL_DEVICE, "w", stdout);

Putting a colon after NUL in the Windows case defends against the possibility that they might, in a future release of Windows, decide that they don't want magic names in every single directory.

I have no idea why "/dev/null" worked in VS2013 - according to everything I know, it shouldn't have.

  1. This worked in VS2013 but crashes in VS2017 (with no OS change). Why is that?

Because MS decided it should change. Nothing in C or C++ requires that either alternative should have the effect you're after, as the interpretation of the first argument to freopen() is implementation-defined. Different implementations can define it differently.

For what it's worth, /dev/null is a UNIXism. Windows does not ordinarily have a file by that name, and it anyway does not provide for device files on the filesystem as UNIX does. Therefore, if your code was working on Windows with MSVC++2013 then that implementation must have been providing special-case behavior for it.

  1. What is the correct way when targeting Windows to redirect all stdout/stderr output to nothing, such that printf produces no visible output?

The Windows device analogous to UNIX /dev/null is named nul (more often written NUL -- like for regular file names, case is not significant). I'd say using that is a pretty good bet, but it's still implementation-dependent.

  1. Is there a safe cross-platform way to do this? I'm not necessarily looking for something inserted into a standard, but rather something that every major desktop target (windows, linux, mac) works with.

This is fundamentally an issue of C or C++ implementation, not of the platform on which that implementation runs. Most implementations do, however, provide for file names used with fopen() and freopen() to have the same significance that they do to the shell and the rest of the operating system. VS2013 seems to be a little odd in that regard, but it does not thereby fail to conform. It follows that no, there is no single file name that has the significance you want to every C and C++ implementation. It is not even guaranteed that there is any file name with that significance.

In practice, you can probably rely on /dev/null for Mac and Linux, and on NUL for Windows. You might then consider using conditional compilation to select one of those based on the compilation environment (see How do I check OS with a preprocessor directive? ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM