9

我的生产代码样机:

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

在 gcc 下工作正常,但据报道无法在 mingw 下编译(需要左值作为一元 '&' 操作数)。

我已经看到设置 FILE* 等于 stdout 便携吗?; 我明白那个

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

将是完全有效的。但是,我需要预设一个全局变量。很遗憾,

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

不适合替换版本1;它甚至不能在 gcc 下编译(第 2 行:初始化元素不是常量)。

知道如何将标准输出放入在 main() 开始之前初始化的变量中吗?

4

3 回答 3

7

在 Linux (glibc) 中,stdout定义如下:

extern struct _IO_FILE *stdout;

所以,你可以用它做任何你需要的事情。

但是,在 MinGW 上,stdout定义如下stdio.h

#define stdout  (&_iob[STDOUT_FILENO])

唉,这不是您可以获取地址的东西,而且,正如您所发现的,它不是您可以在全局初始化程序中使用的东西。:-(

问题的根源在于 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" );
}

这不是一个大的效率问题:无论如何你都必须加载fout,并且与零进行比较非常便宜。

于 2013-08-29T09:37:03.547 回答
6

根据C 标准(7.21.1),stdout是一个宏,它是“指向 FILE 的指针”类型的表达式。它不一定是全局变量。获取其地址不是可移植的 C —— 如您所见,它在 gcc 中工作,但在 mingw 中不工作。

使用您的代码的第二个版本 --- 这是可移植的。

如果您移动了inside的初始化,第三个也可以:foutmain

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

此初始化不能与 的声明结合使用fout,因为stdout它不是(至少,不一定)一个常量表达式。

如果你想有一个FILE **指针,使用:

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

mystdout但是出于同样的原因,不能在其声明处进行初始化。

于 2013-08-29T08:19:17.533 回答
2

我认为这不是一个好主意,因为文件描述符通常不可移植。此外,它使库函数的实现非常低级,否则您将很难同步文件描述符和FILE指针。

但是,正如@JoachimWuttke 明确要求的那样,这就是我在之前的评论中想到的:

/* 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;
}
于 2013-08-29T09:55:26.867 回答