【问题标题】:FILE * ..=stdout : Error initializer element is not constantFILE * ..=stdout:错误初始化元素不是常数
【发布时间】:2016-06-06 09:25:30
【问题描述】:

我的 C 代码如下:

[Linux:/si/usr/hrl]vi test.c    

#include <stdio.h>

FILE * hw = stdout;

int main(void)
{
        return 0;
}

当我在 SUSE 上编译时,它会出现这样的错误:

[Linux:/si/usr/hrl]cc test.c -o test
test.c:3: error: initializer element is not constant

我查看了头文件stdio.h,发现stdout 似乎被定义为一个常量。那么为什么会产生错误呢?顺便说一下,我在 AIX 上编译了相同的代码,它的结果是成功的。

【问题讨论】:

  • 哼。 stdout 在您的 C 标准库实现中是如何定义的?它是什么类型的?
  • 我看起来没那么小心。也许是那个extern struct _IO_FILE *stdout; /* Standard output stream. */。顺便说一下,我用c++编译,编译成功了。
  • @hrl 这个问题与一些人可能会说你的问题是它的副本高度相关:stackoverflow.com/questions/3025050/…

标签: c linux suse


【解决方案1】:

标准不要求stdinstdoutstderr 是常量。

C99 的 n1256 草案在 7.19.1 输入/输出

中说

标题声明 ...
...
TMP_MAX
它扩展为一个整数常量表达式 ...

标准错误 标准输入 标准输出
它们是“指向文件的指针”类型的表达式 ...

(强调我的)

明确指出其他一些值是恒定的,而stdinstdoutstderr 则没有任何说明

所以你必须把初始化放在main中:

#include <stdio.h>

FILE * hw;

int main(void)
{
        hw = stdout;
        ...
        return 0;
}

在 AIX 标准库中,stdout 恰好是一个常量,但它只是一个实现细节,您不能依赖它,因为它可能会在任何新版本中中断。

但是您不应该依赖 stdout 作为变量(甚至是左值),因为它也是 GCC 库中的一个实现细节。


如果您无法更改大部分代码,并且只需要 GCC hack 以使其可编译,您可以尝试使用 gcc constructor attribute 扩展。

gcc documentation提取

6.31 声明函数的属性

在 GNU C 中,您声明有关程序中调用的函数的某些内容,这有助于编译器优化函数调用并更仔细地检查您的代码。

关键字__attribute__ 允许您在进行声明时指定特殊属性。此关键字后跟双括号内的属性说明。当前为所有目标上的函数定义了以下属性: ... ,constructor, ...
...
构造函数属性导致函数在执行进入main()之前被自动调用...

所以你可以使用:

#include <stdio.h>

FILE * hw;

void initHw(void) __attribute__((constructor)) {
    hw = stdout;
}

int main(void)
{
        return 0;
}

但是注意:它是一个 gcc 扩展,这意味着你的代码是正确的 C.

【讨论】:

  • 我知道你的编辑是正确的。但我想寻找一种方法来成功编译它而不在main()中初始化它。因为那是我应该移植到 Suse 的一小部分程序艾克斯。我很难像你说的那样修改真实的代码。
猜你喜欢
  • 2012-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-27
  • 2012-06-04
  • 1970-01-01
  • 2015-07-21
相关资源
最近更新 更多