我的生产代码的样机:
/* version 1 */
#include <stdio.h>
FILE** fout = &stdout;
int main() {
fprintf( *fout, "hello\n" );
}
Run Code Online (Sandbox Code Playgroud)
在gcc下正常工作,但据报道无法在mingw下编译(lvalue需要作为一元'&'操作数).
我看到设置FILE*等于stdout portable吗?; 我明白那个
/* version 2 */
#include <stdio.h>
int main() {
FILE* fout = stdout;
fprintf( fout, "hello\n" );
}
Run Code Online (Sandbox Code Playgroud)
完全有效.但是,我需要预设一个全局变量.不幸,
/* version 3 */
#include <stdio.h>
FILE* fout = stdout;
int main() {
fprintf( fout, "hello\n" );
}
Run Code Online (Sandbox Code Playgroud)
不适合替换版本1; 它甚至不在gcc下编译(第2行:初始化元素不是常量).
知道如何将stdout变为在main()启动之前初始化的变量吗?
在Linux(glibc)中,stdout定义如下:
extern struct _IO_FILE *stdout;
Run Code Online (Sandbox Code Playgroud)
所以,你可以随心所欲地做任何事情.
但是,在MinGW上,stdout定义如下stdio.h:
#define stdout (&_iob[STDOUT_FILENO])
Run Code Online (Sandbox Code Playgroud)
唉,这不是你能得到的地址,而且,正如你所发现的,它不是你可以在全局初始化器中使用的东西.:-(
问题的根源是C标准说这些应该是宏,这意味着任何便携式程序都不应该对内部的内容做出任何假设.所以,我担心,没有简单的方法可以避免以stdout编程方式进行阅读.这就是为什么许多库需要一个lib_initialize()必须先调用的函数.
C++确实允许构造函数用于全局变量,并且这些变量在之前自动调用main,即使对于库也是如此.这是可能的,有gcc,破解一个C程序做同样的,但是这是一个邪恶的把戏,我不记得如何做到这一点从我的头顶.
我只是这样做:
#include <stdio.h>
FILE* fout = NULL;
int my_library_function() {
if (!fout)
fout = stdout;
fprintf( fout, "hello\n" );
}
Run Code Online (Sandbox Code Playgroud)
这不是一个很大的效率问题:fout无论如何你必须加载,与零比较是相当便宜的.
根据C标准(7.21.1),stdout是一个宏,它是"指向FILE的指针"类型的表达式.它不一定是全局变量.如你所见,它不是便携式的C来获取它的地址---它在gcc中工作但在mingw中不起作用.
使用代码的第二个版本---这是可移植的.
如果移动内部的初始化,第三个也可以:foutmain
/* version 3 */
#include <stdio.h>
FILE* fout;
int main() {
fout = stdout;
fprintf( fout, "hello\n" );
}
Run Code Online (Sandbox Code Playgroud)
这种初始化不能与声明相结合fout,因为stdout它不是(至少不一定是)常量表达式.
如果你想要一个FILE **指针,请使用:
/* version 4 */
#include <stdio.h>
FILE* mystdout;
FILE** fout = &mystdout;
int main() {
mystdout = stdout;
fprintf( *fout, "hello\n" );
}
Run Code Online (Sandbox Code Playgroud)
但mystdout由于同样的原因,初始化不能在其声明中.