Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to set a FILE** variable to stdout?

Tags:

c

mingw

Mockup of my production code:

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

Works fine under gcc, but reportedly fails to compile under mingw (lvalue required as unary '&' operand).

I have seen Is setting a FILE* equal to stdout portable?; I understand that

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

would be perfectly valid. However, I need to preset a global variable. Unfortunately,

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

is not suitable to replace version 1; it does not even compile under gcc (line 2: initializer element is not constant).

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

like image 311
Joachim W Avatar asked Aug 29 '13 08:08

Joachim W


People also ask

Is stdout a file pointer?

These three file pointers are automatically defined when a program executes and provide access to the keyboard and screen.

What is stdout in C?

stdout stands for standard output stream and it is a stream which is available to your program by the operating system itself. It is already available to your program from the beginning together with stdin and stderr .

What number is stdout?

Stdout, also known as standard output, is the default file descriptor where a process can write output. In Unix-like operating systems, such as Linux, macOS X, and BSD, stdout is defined by the POSIX standard. Its default file descriptor number is 1.

How to read file from input in C?

Steps To Read A File:Open a file using the function fopen() and store the reference of the file in a FILE pointer. Read contents of the file using any of these functions fgetc(), fgets(), fscanf(), or fread(). File close the file using the function fclose().


2 Answers

In Linux (glibc), stdout is defined like this:

extern struct _IO_FILE *stdout;

So, you can do whatever you need with that.

However, on MinGW, stdout is defined like this, in stdio.h:

#define stdout  (&_iob[STDOUT_FILENO])

Alas, that's not something you can take the address of, and, as you discovered, it's not something you can use in a global initializer. :-(

The root of the problem is that the C standard says that these should be macros, which means any portable program should make no assumptions about what's inside. So, I'm afraid, there is no easy way to avoid doing reading stdout programmatically. This sort of thing is why many libraries require a lib_initialize() function that must be called before anything else.

C++ does permit constructors for global variables, and these are automatically called before main, even for libraries. It is possible, with gcc, to hack a C program to do the same, but that's an evil trick and I can't remember how to do it off the top of my head.

I'd just do this:

#include <stdio.h>
FILE* fout = NULL;

int my_library_function() {
    if (!fout)
      fout = stdout;
    fprintf( fout, "hello\n" );
}

That isn't a big efficiency problem: you'd have to load fout anyway, and a compare with zero is pretty cheap.

like image 151
ams Avatar answered Sep 28 '22 16:09

ams


According to the C standard (7.21.1), stdout is a macro which is an expression of type "pointer to FILE". It is not necessarily a global variable. It is not portable C to take 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 would be OK too if you moved the initialization of fout inside main:

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

This initialization cannot be combined with the declaration of fout, as stdout is 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 the initialization of mystdout cannot be at its declaration, for the same reason.

like image 42
nickie Avatar answered Sep 28 '22 16:09

nickie