2016-02-24 9 views
6

Meine C-Code war wie folgt:FILE * .. = stdout: Fehler initializer Element ist nicht konstant

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

#include <stdio.h> 

FILE * hw = stdout; 

int main(void) 
{ 
     return 0; 
} 

Wenn ich auf SUSE kompilieren, den Fehler so machen:

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

Ich suche nach der Header-Datei stdio.h und finde, dass stdout scheinbar als Konstante definiert wurde. Warum also der Fehler erzeugen? Übrigens, ich kompiliere den gleichen Code unter AIX, es führt zum Erfolg.

+0

Hum. Wie ist 'stdout' in Ihrer C-Standardbibliothek implementiert? Was ist sein Typ? – Bathsheba

+0

Ich sehe nicht so vorsichtig aus. Vielleicht ist es, dass 'extern struct _IO_FILE * stdout;/* Standard-Ausgabestrom. */'. Übrigens benutze ich 'C++' und kompiliere es erfolgreich kompiliert. – hrl

+1

@hrl Diese Frage ist höchst relevant für den Punkt, den einige wahrscheinlich sagen würden, dass Ihre Frage hier ein Duplikat ist: http://StackOverflow.com/Questions/3025050/error-initializer-Element-is-not-constant-when- trying-initialize-variable-w –

Antwort

4

Der Standard erfordert stdin, stdout und stderr nicht als Konstanten.

Der Entwurf n1256 für C99 sagt in 7.19.1 Input/Output <stdio.h>

Der Header erklärt ...
...
TMP_MAX
, die auf eine ganze Zahl erweitert konstanter Ausdruck ...

stderr stdin stdout
die ein re Ausdrücke vom Typ ‚‘ Zeiger auf Datei ‚‘ ...

(betonen Mine)

Es ist ausdrücklich festgestellt, dass einige andere Werte sind konstant, während nichts gesagt wird, für stdin, stdout und stderr

So müssen Sie die Initialisierung in Haupt setzen:

#include <stdio.h> 

FILE * hw; 

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

In der AIX-Standardbibliothek ist stdout eine Konstante, aber es ist nur ein Implementierungsdetail, und Sie können sich nicht darauf verlassen, da es in jeder neueren Version einbrechen könnte.

Aber Sie sollten sich nicht darauf verlassen, dass stdout eine Variable (oder gar ein Lvalue) ist, weil es auch ein Implementierungsdetail in der GCC-Bibliothek ist.


Wenn Sie nicht viel von Ihrem Code ändern können, und müssen nur ein GCC es übersetzbar machen Hack, Sie könnten versuchen, die gcc Konstruktor Attribut Erweiterung zu verwenden.

Auszug aus gcc documentation

6,31 Deklarieren Attribute von Funktionen

In GNU C erklären Sie bestimmte Dinge über in Ihrem Programm aufgerufenen Funktionen, die die Compiler-optimize Funktionsaufrufe helfen und überprüfen Sie den Code genauer.

Mit dem Schlüsselwort __attribute__ können Sie spezielle Attribute angeben, wenn Sie eine Deklaration vornehmen.Auf dieses Schlüsselwort folgt eine Attributspezifikation in doppelten Klammern. Die folgenden Attribute werden derzeit für Funktionen auf alle Ziele definiert: ..., Konstruktor, ...
...
Das Konstruktor Attribut bewirkt, dass die Funktion automatisch aufgerufen werden, bevor die Ausführung main() tritt ...

So könnten Sie verwenden:

#include <stdio.h> 

FILE * hw; 

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

int main(void) 
{ 
     return 0; 
} 

Aber ACHTUNG: es ist eine gcc-Erweiterung, was bedeutet, dass Ihr Code ist nicht korrekte C

+0

Ich weiß, dass Ihre Bearbeitung korrekt ist. Aber ich möchte einen Weg finden, um es erfolgreich zu kompilieren, ohne es in 'main()' zu initialisieren. Weil das ein paar Teile des Programms war, was ich sollte Transplantation von AIX nach Suse. Es ist schwer für mich, den echten Code zu ändern, wie Sie sagen. – hrl

+0

@hrl: GCC hat viele nicht standardmäßige Erweiterungen. Beitrag bearbeitet –