0

When I try to get file descriptor for stderr with fileno(stderr), the result is -2 instead of 2. The documentation for fileno says that that is probably because in a Windows application without a console window stderr is not associated with an output stream.

I need stderr file descriptor because I would like to redirect stderr to pipe using _dup2(), so everything written with fprintf(stderr, "...") and std::cerr << "..." will be redirected to the pipe.

My question is if it is possible to get the file descriptor for stderr in gui application, where there is no console window? Can I somehow open the default stderr file descriptor before calling fileno(stderr)?

EDIT:
I manage to make it work to redirect fprintf(stderr, "...") to pipe by first calling freopen("temp.txt", "w",stderr) and then calling fileno(stderr) to get the file descriptor, based on the idea proposed by @darune.

I wish to do this, because I would like to redirect data from external libraries which are not under my control.

ctrl-alt-delor
  • 7,506
  • 5
  • 40
  • 52
  • 2
    What about simply `dup2(pipeFD, STDERR_FILENO);`? Haven't tested, but should do the trick. – Aconcagua Nov 13 '18 at 11:47
  • I tried to use dup2(pipeFD, 2), because STDERR_FILENO is not defined in Windows. It compiles and runs, but I can't read from the pipe the things I wrote to it. Anyway, it works without problem if I have console application. I assume something with stderr is not initialized properly? – Žiga Golob Nov 13 '18 at 12:57
  • Can you just write to the pipe? Or are you trying to redirect data, that is not under your control? – ctrl-alt-delor Nov 13 '18 at 13:05
  • I thought I had a solution, but it involves `fork` (MS's Windows can't do that). – ctrl-alt-delor Nov 13 '18 at 13:07
  • @ctrl-alt-delor, yes, I would like to redirect data from external libraries which are not under my control. – Žiga Golob Nov 13 '18 at 13:14

2 Answers2

1

std::cerr can be redirected inside your program, but stderr cannot (at least not in any portable or standard way I am aware about).

You can first use std::freopen and after that the valid file descriptor can be obtained with std::_fileno(). That may or may not be enough, so if you need anything else to happen after that point, you are stuck with having to monitor the file from inside your own program (eg. ala. tailing the file) and doing your custom handling.

darune
  • 10,480
  • 2
  • 24
  • 62
  • Hi. I would like to make it with pipes, if it is possible. The solution propsed by Sir Digby Chicken Caesar with [pipes](https://stackoverflow.com/questions/5419356/redirect-stdout-stderr-to-a-string) works if I have console application. I can redirect both, std::cerr and stderr to my custom log, but not if the application has no console window. – Žiga Golob Nov 13 '18 at 13:04
  • @ŽigaGolob You are out of luck Im afraid - like i said you are stuck with the freopen call. However why use stderr to begin with ? I think no one uses stderr for anything really these day. Unless you don't have a choice (why ?). – darune Nov 13 '18 at 13:13
  • As you have said, I don't have a choice because external libraries write errors with `fprintf(stderr, "...")`. Anyway, I would be surprised/can't understand if this is not possible. Why can I do this if I have console application. What is the difference? – Žiga Golob Nov 13 '18 at 13:20
  • 1
    @ŽigaGolob Then you stuck with the `freopen` open call - perhaps if you use that first you may able to apply that other 'hack/solution' that you linked. – darune Nov 13 '18 at 13:25
  • I'm not sure if I understand you how to use `freopen` in my case. Actually I have already tried to redirect `stderr` to two temporary files and read alternately and it was working. Now I want to do this with pipes, if its possible. Do you propose that I first use `freopen` to redirect to physical file and then redirect it to the pipe? – Žiga Golob Nov 13 '18 at 13:38
  • I have tried to use `freopen` first and than redirect to pipe. Now I can read from the pipe everything written with `fprintf(stderr,"...")`. Don't know why I can not read anything written with `std::cerr<<"...\n"` but I can manage that in another way, so I suppose this is the solution for my problem :-). Could you please edit your answer so your idea will be visible/more clear from your answer. Thank you. – Žiga Golob Nov 13 '18 at 13:56
  • @ŽigaGolob not exactly sure what you want added. But feel free to suggest an edit to my answer to better reflect the question. Thank you. – darune Nov 13 '18 at 16:17
0

The way that it works in Unix is that 2 refers to row 2 in a table with in the kernel. This entry in the table can point to and file or file like thing (socket, pipe, file, device, nothing,…). Therefore if there is nothing there, the table slot will still remain, and can be populated with a new value (using dup?).

However this is Unix, and Microsoft's Windows is not Unix.

ctrl-alt-delor
  • 7,506
  • 5
  • 40
  • 52
  • Because this is an explanation of how file-descriptors work. And a note that MS dose not have file-descriptors (It is just faking it). – ctrl-alt-delor Nov 13 '18 at 14:54