在C中初始化一个`FILE *`变量?

时间:2018-05-19 23:12:31

标签: c

我有几个旧的代码库来初始化变量(能够随意重定向输入/输出),如

FILE *usrin = stdin, *usrout = stdout;

然而,gcc(8.1.1,Fedora生牛皮上的glibc 2.27.9000)在这个(initializer is not a compile time constant)bal。我在/usr/include/stdio.h中看到:

extern FILE *stdin;

/* C89/C99 say they're macros. Make them happy */

#define stdin stdin

首先,对我来说没有意义,你不能以这种(相当自然的)方式初始化变量。当然,你可以在以后的代码中完成它,但这是一个麻烦。

第二,为什么宏观扩张不是一个常数?

第三,让它们成为宏的理由是什么?

2 个答案:

答案 0 :(得分:6)

  

首先,对我来说没有意义,你可以用这种(非常自然的)方式初始化变量。

     

第二,为什么宏观扩张不是一个常数?

import errno import sh cmd = sh.Command('./hello.sh') for line in cmd(_iter=True, _iter_noblock=True): if line == errno.EWOULDBLOCK: pass else: print(line) stdinstdout是在C库启动期间初始化的指针,可能是内存分配的结果。它们的值在编译时是不可知的 - 取决于C库的工作方式,它们甚至可能不是常量。 (例如,如果他们指向静态分配的结构,他们的值将受到ASLR的影响。)

  

第三,让它们成为宏的理由是什么?

它保证stderr为真。这可能是为了与一些需要处理缺乏stdio支持的系统的旧程序兼容而添加的。

答案 1 :(得分:3)

经典地,stdinstdoutstderr的值为variations on the theme of

#define stdin (&__iob[0])
#define stdout (&__iob[1])
#define stderr (&__iob[2])

这些是地址常量,可以在文件范围的变量的初始值设定项中使用:

static FILE *def_out = stdout;

但是,C标准并不保证值是可以像C11 §7.21 Input/output <stdio.h.>那样使用的地址常量:

  

stderrstdinstdout
  它是“指向FILE的指针”类型的表达式,它们分别指向与标准错误,输入和输出流关联的FILE对象。

十年或更久以前的某个时候,GNU C库更改了它们的定义,因此您无法再使用stdinstdoutstderr作为文件范围变量的初始化程序,或者具有函数范围的static变量(尽管您可以使用它们来初始化函数中的自动变量)。因此,在许多系统上运行了多年的旧代码已停止在Linux上运行。

stdin等的宏扩展可以是简单的身份扩展(#define stdin stdin)或等效的(在macOS上,#define stdout __stdoutp)。这些是变量,而不是地址常量,因此您无法在文件范围初始值设定项中复制变量的值。这是令人讨厌的,但标准并没有说它们是地址常数,所以它是合法的。

它们必须是宏,因为它们总是宏,所以它保留了与标准I / O库的曙光(大约1978年,早在有标准C库本身之前)的向后兼容性。 / p>