Initialiser des variables avec Stdout et stderr

Initialiser des variables avec Stdout et stderr - C - Programmation

Marsh Posté le 10-11-2005 à 22:18:16    

Slt,
 
J'ai ces 2 lignes de code

Code :
  1. FILE*                err_file = stderr;
  2. FILE*                out_file = stdout;


 
en compilant avec gcc, il me dit:
 

Code :
  1. tri_ft.c:91: error: un élément de l'initialisation n'est pas une constante
  2. tri_ft.c:92: error: un élément de l'initialisation n'est pas une constante


 
stderr et stdout sont des constantes, mais si je caste ca ne change rien, et je ne peux pas mettre FILE* en const.
 
Comment faire pour eviter cela?
 
++

Reply

Marsh Posté le 10-11-2005 à 22:18:16   

Reply

Marsh Posté le 10-11-2005 à 22:54:39    

Comme tu l'as noté, il n'est pas possible de changer FILE * en const, donc il n'est pas possible de faire FILE *err_file = stderr; parce que cela transformerait stderr en quelque chose de non constant, ce qui n'est pas permis.
Par ailleurs, cela ne me parait pas une bonne idée de vouloir masquer stdout et stderr en les renommant, car cela rendra la lecture de tes programmes plus difficiles pour celui qui, plus tard, fera la maintenance de tes programmes.
Cela dit, si tu veux vraiment renommer stdout et stderr, alors tu peux utiliser

#define

.

Reply

Marsh Posté le 10-11-2005 à 23:11:02    

Ba en fait c pas mon programme, j'essais juste de le recompiler. Mais apparemment, FILE *err_file = stderr marchait pour la personne qui fait le programme ? Enfin bref, si comme tu dis c pas possible, alors je mettrais directement stderr et stdout.
 
Merci pour ta réponse
 
++

Reply

Marsh Posté le 11-11-2005 à 01:03:03    

cervantes a écrit :


Code :
  1. FILE*                err_file = stderr;
  2. FILE*                out_file = stdout;


en compilant avec gcc, il me dit:

Code :
  1. tri_ft.c:91: error: un élément de l'initialisation n'est pas une constante
  2. tri_ft.c:92: error: un élément de l'initialisation n'est pas une constante


stderr et stdout sont des constantes,  


Non. ce sont des variables non modifiables. (Non-modifiable l-values)

Citation :


mais si je caste ca ne change rien, et je ne peux pas mettre FILE* en const.
 
Comment faire pour eviter cela?



FILE* err_file;
FILE* out_file;
 
int main (void)
{
   err_file = stderr;
   out_file = stdout;  
 
   return 0;
}



---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 11-11-2005 à 04:16:19    

En fait ce n'est pas vraiment que ce sont des variables non modifiables (elles sont modifiables, dans un bloc). C'est surtout que ce sont des variables dont la valeur n'est pas connue à la compilation. Si tu veux savoir ce qui se passe exactement, stdout et stderr sont déclarés de la façon suivante dans stdio.h :

Code :
  1. extern struct _IO_FILE *stdout;
  2. extern struct _IO_FILE *stderr;


Ce qui veut dire que ce les addresses des deux structures _IO_FILE en question sont définies dans un autre module (une autre unité de compilation), et ne sont pas connues au moment ou le compilateur compile ton module. Maintenant le truc qu'il faut bien comprendre, c'est que pour initialiser une variable globale, le compilateur doit absolument connaitre la valeur d'initialisation au moment ou il compile le module en question, parce que la valeur est écrite directement en dur dans le binaire. Ce n'est pas le cas ici, d'où l'erreur.
 
Maintenant, pourquoi ça marche en initialisant err_file et out_file dans un bloc, comme le propose Emmanuel ? Parce que pour faire ça, le compilateur n'a pas besoin de connaitre la valeur d'initialisation au moment ou il compile le module. Tout ce que le compilateur a besoin de savoir, c'est que cette valeur est définie quelque par dans un autre module (ce que lui dit le "extern" ). Dans ce cas il n'écrit pas la valeur directement dans le binaire; il génère juste un petit bout de code qui va chercher une addresse dans une zone spéciale (appelons cette zone "TOC" comme Table Of Content), puis lit la valeur à cette adresse, et l'assigne enfin à err_file. L'adresse qui se trouve dans la TOC est écrite soit par l'éditeur de lien (donc au moment du link) si tu te lie statiquement avec le module qui contient la valeur d'initialisation, soit par le loader (donc au chargement de ton programme) si tu te lie dynamiquement avec ce module (ce qui est le cas ici mais ne change rien au problème).
 
Edit : si tu veux un exemple minimal, le module suivant ne compile pas non plus, pour la même raison (à compiler avec -c) :

Code :
  1. extern int machin;
  2. int bidule = machin;

Message cité 1 fois
Message édité par matafan le 11-11-2005 à 04:42:48
Reply

Marsh Posté le 11-11-2005 à 09:40:09    

matafan a écrit :

En fait ce n'est pas vraiment que ce sont des variables non modifiables (elles sont modifiables, dans un bloc). C'est surtout que ce sont des variables dont la valeur n'est pas connue à la compilation.


Oui, et c'est ça le noeud du problème.

Citation :


 Si tu veux savoir ce qui se passe exactement, stdout et stderr sont déclarés de la façon suivante dans stdio.h :

Code :
  1. extern struct _IO_FILE *stdout;
  2. extern struct _IO_FILE *stderr;




Ca, c'est pour une implémentation particulière. Le langage C ne précise pas comment sont définies ces valeurs.
 
cygwin


#ifndef _REENT_ONLY
#define stdin (_REENT->_stdin)
#define stdout (_REENT->_stdout)
#define stderr (_REENT->_stderr)
#else /* _REENT_ONLY */
#define stdin (_impure_ptr->_stdin)
#define stdout (_impure_ptr->_stdout)
#define stderr (_impure_ptr->_stderr)
#endif /* _REENT_ONLY */


mingw


#define stdin (&_iob[STDIN_FILENO])
#define stdout (&_iob[STDOUT_FILENO])
#define stderr (&_iob[STDERR_FILENO])


Code Composer (DSP Texas Instrument)


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


Borland C


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


Diab (Power PC)


#define stdin   (_lc_f_addr(0))
#define stdout  (_lc_f_addr(1))
#define stderr  (_lc_f_addr(2))


Visual C++


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


Pelles C


#ifndef _WINCE
#define stdin   (&__stdin)
#define stdout  (&__stdout)
#define stderr  (&__stderr)
#else /* _WINCE */
#define stdin  _getstdfilex(0)
#define stdout  _getstdfilex(1)
#define stderr  _getstdfilex(2)
#endif /* _WINCE */



Message édité par Emmanuel Delahaye le 11-11-2005 à 10:06:55

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 11-11-2005 à 16:30:26    

Je n'en demandais pas autant mais merci pour toutes ces précisions. Maintenant tout est clair et en effet ca marche tres bien en modifiant comme ci dessus.
 
++

Reply

Marsh Posté le 12-11-2005 à 05:20:17    

Emmanuel Delahaye a écrit :


FILE* err_file;
FILE* out_file;
 
int main (void)
{
   err_file = stderr;
   out_file = stdout;  
 
   return 0;
}



 
Hallucine je ? Mais non... je ne rève pas. Emmanuel a réellement déclaré ces variables en global. :bounce:  :bounce:  :lol:  


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 12-11-2005 à 09:09:32    

On n'a pas le choix si on veut assigner stdin et stderr à des variables. :/
 
Par contre si c'est pour assigner des flux par défaut à un programme acceptant des noms de fichier en paramètres non obligatoires, j'aurais plutôt utilisé freopen() si les arguments sont précisés. Comme ça on utilise stdin et stderr tout le long du programme, et il n'y a pas de bidouille comme ici.

Reply

Marsh Posté le 12-11-2005 à 10:11:29    

Dans mon cas, c'est pour utiliser avec fprintf() uniquement, dc j'ai pas 36 solutions vu qu'elle est déclaré comme ceci:
 

Code :
  1. int fprintf( FILE *stream, const char *format [, argument ]...);

Reply

Marsh Posté le 12-11-2005 à 10:11:29   

Reply

Marsh Posté le 12-11-2005 à 10:55:30    

cervantes a écrit :

Dans mon cas, c'est pour utiliser avec fprintf() uniquement, dc j'ai pas 36 solutions vu qu'elle est déclaré comme ceci:
 

Code :
  1. int fprintf( FILE *stream, const char *format [, argument ]...);



Qu'est-ce qui empêche de faire

fprintf (stdout, "hello world\" );


ou

fprintf (stderr, "hello world\" );


 


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed