dup2

Discussion in 'C++' started by Hongliang Wang, Apr 22, 2014.

  1. Hell all,

    I was trying to redirect stdout to a file by using dup2. First I followed microsoft example: http://msdn.microsoft.com/en-us/library/8syseb29.aspx

    it just works fine.

    Then I tried to implement this in my own class (ABCLog) but stdout is not captured. I cannot figure it out. The only reason I could think of is that main() is in main.cpp while class ABCLog are in separate files (ABCLog.cpp and ABCLog.h). Could anybody confirm this please?

    int main(int argc, char *argv[])
    {
    ABCLog *log = new ABCLog();

    puts("in main");
    fflush( stdout );

    delete log;

    return 0;
    }

    ABCLog::ABCLog(const char *logFileName)
    {
    old = _dup(1); /* "old" refers to stdout */
    if(old == -1) {
    perror(ERR_000104_DUP);
    exit(1);
    }

    if( fopen_s( &logFile, logFileName, "a" ) != 0 ) {
    fprintf(stderr, ERR_000105_LOG_FILE_OPEN, logFileName);
    exit( 1 );
    }

    if( -1 == _dup2( _fileno( logFile ), 1 ) ) {
    perror( ERR_000106_DUP2 );
    exit( 1 );
    }

    puts("in ABCLog");
    fflush(stdout);
    }

    /**
    * Destructor
    */
    ABCLog::~ABCLog()
    {
    _dup2( old, 1 );
    _flushall();
    m_stream.close();
    }
     
    Hongliang Wang, Apr 22, 2014
    #1
    1. Advertisements

  2. On Tue, 22 Apr 2014 01:35:06 -0700 (PDT), Hongliang Wang
    <> wrote:

    >Hell all,
    >
    >I was trying to redirect stdout to a file by using dup2. First I followed microsoft example: http://msdn.microsoft.com/en-us/library/8syseb29.aspx
    >
    >it just works fine.
    >
    >Then I tried to implement this in my own class (ABCLog) but stdout is not captured. I cannot figure it out. The only reason I could think of is that main() is in main.cpp while class ABCLog are in separate files (ABCLog.cpp and ABCLog.h). Could anybody confirm this please?
    >
    >int main(int argc, char *argv[])
    >{
    > ABCLog *log = new ABCLog();
    >
    > puts("in main");
    > fflush( stdout );
    >
    > delete log;
    >
    > return 0;
    >}
    >
    >ABCLog::ABCLog(const char *logFileName)


    Is this constructor ever called? Your dynamic allocation does not
    specify an argument that matches this parameter list.

    >{
    > old = _dup(1); /* "old" refers to stdout */
    > if(old == -1) {
    > perror(ERR_000104_DUP);
    > exit(1);
    > }
    >
    > if( fopen_s( &logFile, logFileName, "a" ) != 0 ) {
    > fprintf(stderr, ERR_000105_LOG_FILE_OPEN, logFileName);
    > exit( 1 );
    > }
    >
    > if( -1 == _dup2( _fileno( logFile ), 1 ) ) {
    > perror( ERR_000106_DUP2 );
    > exit( 1 );
    > }
    >
    > puts("in ABCLog");
    > fflush(stdout);
    >}
    >
    >/**
    > * Destructor
    > */
    >ABCLog::~ABCLog()
    >{
    > _dup2( old, 1 );
    > _flushall();
    > m_stream.close();
    >}


    --
    Remove del for email
     
    Barry Schwarz, Apr 22, 2014
    #2
    1. Advertisements

  3. Yes, the constructor is being called because there is only one declaration as follows:

    ABCLog(const char *logFileName = "log.txt");
     
    Hongliang Wang, Apr 23, 2014
    #3
  4. On Tue, 22 Apr 2014 18:55:23 -0700 (PDT), Hongliang Wang
    <> wrote:

    >Yes, the constructor is being called because there is only one declaration as follows:
    >
    >ABCLog(const char *logFileName = "log.txt");


    That line of code does not exist in your original post.

    --
    Remove del for email
     
    Barry Schwarz, Apr 23, 2014
    #4
  5. Hongliang Wang

    Paul N Guest

    On Tuesday, 22 April 2014 09:35:06 UTC+1, Hongliang Wang wrote:
    > Hell all,
    >
    >
    >
    > I was trying to redirect stdout to a file by using dup2. First I followedmicrosoft example: http://msdn.microsoft.com/en-us/library/8syseb29.aspx
    >
    >
    >
    > it just works fine.
    >
    >
    >
    > Then I tried to implement this in my own class (ABCLog) but stdout is notcaptured. I cannot figure it out. The only reason I could think of is thatmain() is in main.cpp while class ABCLog are in separate files (ABCLog.cppand ABCLog.h). Could anybody confirm this please?
    >
    >
    >
    > int main(int argc, char *argv[])
    >
    > {
    >
    > ABCLog *log = new ABCLog();
    >
    >
    >
    > puts("in main");
    >
    > fflush( stdout );
    >
    >
    >
    > delete log;
    >
    >
    >
    > return 0;
    >
    > }
    >
    >
    >
    > ABCLog::ABCLog(const char *logFileName)
    >
    > {
    >
    > old = _dup(1); /* "old" refers to stdout */
    >
    > if(old == -1) {
    >
    > perror(ERR_000104_DUP);
    >
    > exit(1);
    >
    > }
    >
    >
    >
    > if( fopen_s( &logFile, logFileName, "a" ) != 0 ) {
    >
    > fprintf(stderr, ERR_000105_LOG_FILE_OPEN, logFileName);
    >
    > exit( 1 );
    >
    > }
    >
    >
    >
    > if( -1 == _dup2( _fileno( logFile ), 1 ) ) {
    >
    > perror( ERR_000106_DUP2 );
    >
    > exit( 1 );
    >
    > }
    >
    >
    >
    > puts("in ABCLog");
    >
    > fflush(stdout);
    >
    > }
    >
    >
    >
    > /**
    >
    > * Destructor
    >
    > */
    >
    > ABCLog::~ABCLog()
    >
    > {
    >
    > _dup2( old, 1 );
    >
    > _flushall();
    >
    > m_stream.close();
    >
    > }


    Other people have explained this, but perhaps not clearly enough, so I'll have a go.

    In main, the object is brought into existence, but it then is destroyed without the program doing anything to it. Strange as it may seem, this means that the compiler is allowed to not create the object at all. So you don't get the side effects from the constructor and the destructor that you were hoping for.

    So - is the constructor actually being run? You could test this for exampleby putting an output command or a beep into the constructor - does the computer actually beep when you run it?

    From your last reply, it seems that you are answering the question of whether the constructor runs simply by looking at the code and saying "but surely it must do?" Don't do that - actually test it.

    Hope this helps.
    Paul.
     
    Paul N, Apr 23, 2014
    #5
  6. Hongliang Wang

    Guest

    On Wednesday, April 23, 2014 2:44:24 PM UTC-5, Paul N wrote:
    >
    > Other people have explained this, but perhaps not clearly enough, so I'llhave a go.
    >
    > In main, the object is brought into existence, but it then is destroyed without the program doing anything to it. Strange as it may seem, this meansthat the compiler is allowed to not create the object at all. So you don'tget the side effects from the constructor and the destructor that you werehoping for.
    >


    do{
    assert(!pendingTransactions.empty());
    auto const& request=*pendingTransactions.front();
    if(cmwBuf.GiveBool()){
    setDirectory(request.path.c_str());
    empty_container<File>{cmwBuf};
    save_lastruntime(request.filename_with_extension.c_str()
    ,request.latest_update);
    middle_messages_front::Marshal(localsendbuf,true);
    }else
    middle_messages_front::Marshal(localsendbuf,false
    ,cmwBuf.GiveCharStar());
    localsendbuf.Flush((sockaddr*)&request.front_tier
    ,sizeof(request.front_tier));
    pendingTransactions.pop_front();
    }while(cmwBuf.NextMessage());


    The empty_container there is just constructed. Gcc and Clang
    both keep the ctor in at least from what I can tell.

    I think it'd be lame to have to add a no-op function and
    call it just to keep the compiler from removing the ctor.


    Brian
    Ebenezer Enterprises - In G-d we trust.
    http://webEbenezer.net
     
    , Apr 24, 2014
    #6
  7. Hongliang Wang

    Jorgen Grahn Guest

    On Wed, 2014-04-23, Paul N wrote:
    > On Tuesday, 22 April 2014 09:35:06 UTC+1, Hongliang Wang wrote:


    >> [snipped because I cannot be bothered to fix the formatting]


    > Other people have explained this, but perhaps not clearly enough, so
    > I'll have a go.


    > In main, the object is brought into existence, but it then is
    > destroyed without the program doing anything to it. Strange as it may
    > seem, this means that the compiler is allowed to not create the object
    > at all. So you don't get the side effects from the constructor and the
    > destructor that you were hoping for.


    Huh? Then how can the pattern with RAII mutex locks work?

    void foo()
    {
    Lock lock(some_mutex);
    do_stuff_that_needs_locking();
    }

    I've always assumed the compiler must obey (create 'lock', and do it
    before calling the other function) in this case, not take a chance on
    the constructor having no side effects. (Modulo the as-if rule, of
    course.)

    (I'm vaguely aware that copy construction is a special case and that
    it's a Bad Idea to treat that one as any other function.)

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Apr 24, 2014
    #7
  8. Hongliang Wang

    David Brown Guest

    On 24/04/14 11:43, Jorgen Grahn wrote:
    > On Wed, 2014-04-23, Paul N wrote:
    >> On Tuesday, 22 April 2014 09:35:06 UTC+1, Hongliang Wang wrote:

    >
    >>> [snipped because I cannot be bothered to fix the formatting]

    >
    >> Other people have explained this, but perhaps not clearly enough, so
    >> I'll have a go.

    >
    >> In main, the object is brought into existence, but it then is
    >> destroyed without the program doing anything to it. Strange as it may
    >> seem, this means that the compiler is allowed to not create the object
    >> at all. So you don't get the side effects from the constructor and the
    >> destructor that you were hoping for.

    >
    > Huh? Then how can the pattern with RAII mutex locks work?
    >
    > void foo()
    > {
    > Lock lock(some_mutex);
    > do_stuff_that_needs_locking();
    > }
    >
    > I've always assumed the compiler must obey (create 'lock', and do it
    > before calling the other function) in this case, not take a chance on
    > the constructor having no side effects. (Modulo the as-if rule, of
    > course.)
    >
    > (I'm vaguely aware that copy construction is a special case and that
    > it's a Bad Idea to treat that one as any other function.)
    >
    > /Jorgen
    >


    It all depends on observable effects - accessing volatiles, calls to
    externally defined functions, exiting the program, and inline assembly.
    If the compiler knows for sure that a particular expression (including
    the construction of an object) does not have any influence on the
    observable effects of the program, then it can remove that expression.
    And if that means all actions on a variable is removed, then the
    variable can be removed.

    But if the compiler is in any doubt about the observable effects, then
    it needs to generate the code in the order guaranteed to follow those
    observable effects. So if Lock's constructor has such effects (and it
    almost certainly will, to be of much use), then your lock gets created.
    And if do_stuff_that_needs_locking() has any such effects (ant it
    almost certainly will, or you wouldn't need the lock), it happens after
    the Lock is created and before it is destroyed.

    It is possible for things to be re-arranged, however. If you had this:

    int protectedData;
    static void do_stuff_that_needs_locking() {
    int x = 0;
    for (int i = 0; i < 1000; i++) {
    x += i;
    }
    protectedData = x;
    }

    Then the compiler /could/ generate this:

    void foo() {
    int x = 0;
    for (int i = 0; i < 1000; i++) {
    x += i;
    }
    Lock lock(some_mutex);
    protectedData = x;
    // Destruct lock
    }
     
    David Brown, Apr 24, 2014
    #8
  9. Hongliang Wang

    Jorgen Grahn Guest

    On Thu, 2014-04-24, David Brown wrote:
    > On 24/04/14 11:43, Jorgen Grahn wrote:
    >> On Wed, 2014-04-23, Paul N wrote:
    >>> On Tuesday, 22 April 2014 09:35:06 UTC+1, Hongliang Wang wrote:

    >>
    >>>> [snipped because I cannot be bothered to fix the formatting]

    >>
    >>> Other people have explained this, but perhaps not clearly enough, so
    >>> I'll have a go.

    >>
    >>> In main, the object is brought into existence, but it then is
    >>> destroyed without the program doing anything to it. Strange as it may
    >>> seem, this means that the compiler is allowed to not create the object
    >>> at all. So you don't get the side effects from the constructor and the
    >>> destructor that you were hoping for.

    >>
    >> Huh? Then how can the pattern with RAII mutex locks work?
    >>
    >> void foo()
    >> {
    >> Lock lock(some_mutex);
    >> do_stuff_that_needs_locking();
    >> }
    >>
    >> I've always assumed the compiler must obey (create 'lock', and do it
    >> before calling the other function) in this case, not take a chance on
    >> the constructor having no side effects. (Modulo the as-if rule, of
    >> course.)
    >>
    >> (I'm vaguely aware that copy construction is a special case and that
    >> it's a Bad Idea to treat that one as any other function.)
    >>
    >> /Jorgen
    >>

    >
    > It all depends on observable effects - accessing volatiles, calls to
    > externally defined functions, exiting the program, and inline assembly.
    > If the compiler knows for sure that a particular expression (including
    > the construction of an object) does not have any influence on the
    > observable effects of the program, then it can remove that expression.
    > And if that means all actions on a variable is removed, then the
    > variable can be removed.
    >
    > But if the compiler is in any doubt about the observable effects, then
    > it needs to generate the code in the order guaranteed to follow those
    > observable effects. So if Lock's constructor has such effects (and it
    > almost certainly will, to be of much use), then your lock gets created.
    > And if do_stuff_that_needs_locking() has any such effects (ant it
    > almost certainly will, or you wouldn't need the lock), it happens after
    > the Lock is created and before it is destroyed.
    >
    > It is possible for things to be re-arranged, however. If you had this:
    >
    > int protectedData;
    > static void do_stuff_that_needs_locking() {
    > int x = 0;
    > for (int i = 0; i < 1000; i++) {
    > x += i;
    > }
    > protectedData = x;
    > }
    >
    > Then the compiler /could/ generate this:
    >
    > void foo() {
    > int x = 0;
    > for (int i = 0; i < 1000; i++) {
    > x += i;
    > }
    > Lock lock(some_mutex);
    > protectedData = x;
    > // Destruct lock
    > }


    Sure. My brain files all that under "as if", especially in C++98's
    memory model.

    So I suppose you implicitly agree with me, that Paul N's explanation
    above is incorrect, given that the OP's constructor was full of
    observable effects? That's mainly what I want to establish.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Apr 24, 2014
    #9
  10. Hongliang Wang

    David Brown Guest

    On 24/04/14 17:16, Jorgen Grahn wrote:
    > On Thu, 2014-04-24, David Brown wrote:
    >> On 24/04/14 11:43, Jorgen Grahn wrote:
    >>> On Wed, 2014-04-23, Paul N wrote:
    >>>> On Tuesday, 22 April 2014 09:35:06 UTC+1, Hongliang Wang wrote:
    >>>
    >>>>> [snipped because I cannot be bothered to fix the formatting]
    >>>
    >>>> Other people have explained this, but perhaps not clearly enough, so
    >>>> I'll have a go.
    >>>
    >>>> In main, the object is brought into existence, but it then is
    >>>> destroyed without the program doing anything to it. Strange as it may
    >>>> seem, this means that the compiler is allowed to not create the object
    >>>> at all. So you don't get the side effects from the constructor and the
    >>>> destructor that you were hoping for.
    >>>
    >>> Huh? Then how can the pattern with RAII mutex locks work?
    >>>
    >>> void foo()
    >>> {
    >>> Lock lock(some_mutex);
    >>> do_stuff_that_needs_locking();
    >>> }
    >>>
    >>> I've always assumed the compiler must obey (create 'lock', and do it
    >>> before calling the other function) in this case, not take a chance on
    >>> the constructor having no side effects. (Modulo the as-if rule, of
    >>> course.)
    >>>
    >>> (I'm vaguely aware that copy construction is a special case and that
    >>> it's a Bad Idea to treat that one as any other function.)
    >>>
    >>> /Jorgen
    >>>

    >>
    >> It all depends on observable effects - accessing volatiles, calls to
    >> externally defined functions, exiting the program, and inline assembly.
    >> If the compiler knows for sure that a particular expression (including
    >> the construction of an object) does not have any influence on the
    >> observable effects of the program, then it can remove that expression.
    >> And if that means all actions on a variable is removed, then the
    >> variable can be removed.
    >>
    >> But if the compiler is in any doubt about the observable effects, then
    >> it needs to generate the code in the order guaranteed to follow those
    >> observable effects. So if Lock's constructor has such effects (and it
    >> almost certainly will, to be of much use), then your lock gets created.
    >> And if do_stuff_that_needs_locking() has any such effects (ant it
    >> almost certainly will, or you wouldn't need the lock), it happens after
    >> the Lock is created and before it is destroyed.
    >>
    >> It is possible for things to be re-arranged, however. If you had this:
    >>
    >> int protectedData;
    >> static void do_stuff_that_needs_locking() {
    >> int x = 0;
    >> for (int i = 0; i < 1000; i++) {
    >> x += i;
    >> }
    >> protectedData = x;
    >> }
    >>
    >> Then the compiler /could/ generate this:
    >>
    >> void foo() {
    >> int x = 0;
    >> for (int i = 0; i < 1000; i++) {
    >> x += i;
    >> }
    >> Lock lock(some_mutex);
    >> protectedData = x;
    >> // Destruct lock
    >> }

    >
    > Sure. My brain files all that under "as if", especially in C++98's
    > memory model.
    >
    > So I suppose you implicitly agree with me, that Paul N's explanation
    > above is incorrect, given that the OP's constructor was full of
    > observable effects? That's mainly what I want to establish.
    >


    Yes, I agree with you - and I agree it is all "as if". I really wanted
    to point out that "as if" allows things to be split up and moved around
    in the manner shown above - that catches many people out. (It will not
    normally affect the correctness of your code, unless you are doing
    something odd and haven't taken appropriate measures to control the
    order of the code, but it can be a surprise during debugging or
    examining the object code.)
     
    David Brown, Apr 24, 2014
    #10
  11. Hongliang Wang

    Jorgen Grahn Guest

    On Thu, 2014-04-24, David Brown wrote:
    > On 24/04/14 17:16, Jorgen Grahn wrote:
    >> On Thu, 2014-04-24, David Brown wrote:
    >>> On 24/04/14 11:43, Jorgen Grahn wrote:

    ....
    >>>> void foo()
    >>>> {
    >>>> Lock lock(some_mutex);
    >>>> do_stuff_that_needs_locking();
    >>>> }

    ....

    >>> It is possible for things to be re-arranged, however. If you had this:
    >>>
    >>> int protectedData;
    >>> static void do_stuff_that_needs_locking() {
    >>> int x = 0;
    >>> for (int i = 0; i < 1000; i++) {
    >>> x += i;
    >>> }
    >>> protectedData = x;
    >>> }
    >>>
    >>> Then the compiler /could/ generate this:
    >>>
    >>> void foo() {
    >>> int x = 0;
    >>> for (int i = 0; i < 1000; i++) {
    >>> x += i;
    >>> }
    >>> Lock lock(some_mutex);
    >>> protectedData = x;
    >>> // Destruct lock
    >>> }

    >>
    >> Sure. My brain files all that under "as if", especially in C++98's
    >> memory model.

    ....

    > Yes, I agree with you - and I agree it is all "as if". I really wanted
    > to point out that "as if" allows things to be split up and moved around
    > in the manner shown above - that catches many people out. (It will not
    > normally affect the correctness of your code, unless you are doing
    > something odd and haven't taken appropriate measures to control the
    > order of the code, but it can be a surprise during debugging or
    > examining the object code.)


    True. And your example above /did/ frighten me for a few seconds.
    Then I was relieved to see that it fit in my mental model after all,
    which was nice.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Apr 25, 2014
    #11
  12. Hongliang Wang

    James Kanze Guest

    On Wednesday, 23 April 2014 20:44:24 UTC+1, Paul N wrote:
    > On Tuesday, 22 April 2014 09:35:06 UTC+1, Hongliang Wang wrote:


    > In main, the object is brought into existence, but it then is
    > destroyed without the program doing anything to it. Strange as
    > it may seem, this means that the compiler is allowed to not
    > create the object at all. So you don't get the side effects
    > from the constructor and the destructor that you were hoping
    > for.


    In main, the object is created with a new expression. The
    compiler is *not* allowed to suppress this.

    Using a local variable would, of course, be more idiomatic (and
    correspond to the widely used RAII idiom).

    --
    James
     
    James Kanze, Apr 28, 2014
    #12
  13. Yes I am sure that constructor is called, because a new file 'log.txt' is being created.

    I have two test messages, one is in main and another one is in class constructor. But 'log.txt' is unable to capture either of them:- its length is zero.
     
    Hongliang Wang, Apr 29, 2014
    #13
  14. Hongliang Wang

    red floyd Guest

    On 4/29/2014 12:53 AM, Hongliang Wang wrote:
    > Yes I am sure that constructor is called, because a new file 'log.txt' is being created.
    >
    > I have two test messages, one is in main and another one is in class constructor. But 'log.txt' is unable to capture either of them:- its length is zero.
    >


    Mixing file descriptors and iostreams (or stdio) can often lead to
    counterintuitve results. That's why the C library has freopen().
    Use that, instead of dup/dup2.

    Alternatively, use IOStreams, and create a new streambuf for
    the log file, and assign that to std::cout.
     
    red floyd, Apr 29, 2014
    #14
  15. Thank you red. freopen works.
     
    Hongliang Wang, Apr 30, 2014
    #15
    1. Advertisements

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Similar Threads
  1. PC

    pipe() dup2() fork() execl() select()

    PC, Aug 9, 2003, in forum: C Programming
    Replies:
    3
    Views:
    1,682
  2. Help with open, dup and dup2

    , Mar 16, 2006, in forum: C Programming
    Replies:
    2
    Views:
    545
    Ian Collins
    Mar 16, 2006
  3. DyslexicAnaboko

    problems redirecting an open file to stdin using dup2()

    DyslexicAnaboko, Dec 5, 2006, in forum: C Programming
    Replies:
    4
    Views:
    998
    DyslexicAnaboko
    Dec 5, 2006
Loading...