How to set FILE ** variable in stdout?

Layout of my production code:

/* version 1 */ #include <stdio.h> FILE** fout = &stdout; int main() { fprintf( *fout, "hello\n" ); } 

It works fine under gcc, but reportedly cannot compile under mingw (lvalue, required as the unary operand "&").

Have I seen FILE * set to equal standard portable devices? ; I understand that

 /* version 2 */ #include <stdio.h> int main() { FILE* fout = stdout; fprintf( fout, "hello\n" ); } 

will be absolutely correct. However, I need to set a global variable. Unfortunately,

 /* version 3 */ #include <stdio.h> FILE* fout = stdout; int main() { fprintf( fout, "hello\n" ); } 

not suitable for version 1 replacement; it does not even compile under gcc (line 2: the initialization element is not a constant).

Any idea how to get stdout into a variable initialized before main () is run?

+6
source share
3 answers

On Linux (glibc), stdout is defined as follows:

 extern struct _IO_FILE *stdout; 

So, you can do whatever you need.

However, on MinGW, stdout is defined as follows: stdio.h :

 #define stdout (&_iob[STDOUT_FILENO]) 

Alas, you cannot accept the address, and as you have discovered, this is not something you can use in the global initializer. :-(

The root of the problem is that the C standard states that these should be macros, which means that any portable program should not make any assumptions about what's inside. So, I'm afraid there is no easy way to avoid stdout programming programmatically. This is because many libraries require the lib_initialize() function, which must be called first.

C ++ allows constructors for global variables, and they are automatically called before main even for libraries. It is possible with gcc to hack a C program to do the same, but this is an evil trick, and I cannot remember how to do it from the head.

I would just do this:

 #include <stdio.h> FILE* fout = NULL; int my_library_function() { if (!fout) fout = stdout; fprintf( fout, "hello\n" ); } 

This is not a big performance issue: you still have to load fout , and comparing with zero is pretty cheap.

+6
source

According to the C standard (7.21.1), stdout is a macro that is an expression like “pointer to FILE”. This is not necessarily a global variable. It is not portable C to accept its address --- it works in gcc, but not in mingw, as you saw.

Use the second version of your code --- this is portable.

The third one will also be OK if you moved the initialization fout inside main :

 /* version 3 */ #include <stdio.h> FILE* fout; int main() { fout = stdout; fprintf( fout, "hello\n" ); } 

This initialization cannot be combined with a fout declaration, since stdout not (at least, not necessarily) a constant expression.

If you want to have a FILE ** pointer, use:

 /* version 4 */ #include <stdio.h> FILE* mystdout; FILE** fout = &mystdout; int main() { mystdout = stdout; fprintf( *fout, "hello\n" ); } 

but again, mystdout initialization cannot be in the declaration for the same reason.

+5
source

I do not think this is a very good idea, since file descriptors are usually not portable. In addition, this makes the implementation of library functions rather low-level, or you will have complex synchronization of file descriptors and FILE pointers.

However, as @JoachimWuttke explicitly asked, here is what I meant in my previous comment:

 /* version 5 */ #include <stdio.h> #include <unistd.h> int fdout = 1; void use(FILE *fout) { fdout = fileno(fout); } void printing() { const char msg[] = "hello\n"; write(fdout, msg, sizeof(msg)-1); } int main() { printing(); // this one goes to stdout FILE *f = fopen("output.txt", "wt"); use(f); printing(); // this one goes to "output.txt" printing(); // this one too fclose(f); use(stdout); printing(); // this one goes to stdout too return 0; } 
+2
source

Source: https://habr.com/ru/post/952718/


All Articles