dup2


H

Hongliang Wang

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();
}
 
Ad

Advertisements

B

Barry Schwarz

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.
 
H

Hongliang Wang

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

ABCLog(const char *logFileName = "log.txt");
 
B

Barry Schwarz

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.
 
P

Paul N

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.
 
W

woodbrian77

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
 
Ad

Advertisements

J

Jorgen Grahn

[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
 
D

David Brown

[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
}
 
J

Jorgen Grahn

[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
 
D

David Brown

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.)
 
J

Jorgen Grahn

....
....

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
 
Ad

Advertisements

J

James Kanze

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).
 
H

Hongliang Wang

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.
 
R

red floyd

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.
 
Ad

Advertisements


Ask a Question

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. After that, you can post your question and our members will help you out.

Ask a Question

Top