éternel débutant en C pour mon plaisir, je me permets de venir vous
demander quelques éclaircissements sur une situation que je n'arrive pas
à comprendre :
J'utilise le cours en ligne spécial "grand débutant" du "site du zéro" :
<http://www.siteduzero.com/tutoriel-3-14189-apprenez-a-programmer-en-c.html>
Je réalise les exercices du cours dans deux environnements différents :
- sous windows vista avec l'IDE visual C++ 2008 express
- sous linux ubuntu 9.04 avec gcc
J'ai écrit un programme dans le cadre des exercices proposés sur les
tableaux par ce cours en ligne. Le fichier en question peut être
téléchargé ici :
< http://dl.free.fr/to7PFReLM/tableau.c>
Ce qui m'étonne, c'est que j'arrive à compiler sans difficulté ce code
sous Linux, et que le programme se comporte exactement comme je le
souhaite. Par contre, sous Windows, impossible de compiler, l'IDE me
renvoie 42 erreurs et 31 avertissements !!! La plupart des erreurs
semblent être liées aux variables. Par exemple :
"erreur de syntaxe : absence de ';' avant 'type'"
"identificateur non déclaré"
Or, j'ai beau lire et relire mon code, les variables me sembles toutes
déclarées correctement et il ne manque à mon sens pas de ";" en fin
d'instructions. De plus, comme je le disais au début, le même code se
compile sans aucune erreur sous Linux ...
Alors, comment expliquer que deux compilateurs réagissent aussi
différemment, et où et mon erreur ?
Merci par avance du temps que vous pourrez me consacrer,
| Le 14/09/2009 20:01, Marc Espie a écrit : | > In article<4aae4785$0$12643$, | > Richard Delorme wrote: | >> Le 14/09/2009 14:56, Marc Espie a écrit : | >> | >>> dans tous les cas ou ils finissent par tomber sur des cas ou "ca serait | >>> bien", j'essaie de leur expliquer que c'est un ECHEC de conception, ou le | >>> developpeur n'a pas reussi a faire assez simple (et de mon point de vue, | >>> on en trouve meme dans la bibliotheque standard, FILE * est une grosse | >>> connerie, a mon avis). | >> | >> En quel sens FILE est une connerie ? | > | > Par exemple, ca te rend impossible de prototyper une fonction qui prend | > un fichier ouvert en parametre sans inclure stdio.h... | > | > si c'est une fonction qui le manipule comme handle opaque, et qui se contente | > de le passer a une autre fonction, c'est tres cretin. | | Si j'ai bien compris, tu veux dire que si l'on avait, par exemple, un | "struct file_t" au lieu de FILE, ça allégerait un peu certains | codes. Pourquoi pas.
avons-nous des exemples de ces codes qui seraient allégés ?
Moi j'en ai deja eu sous la main, style une fonction qui prend un FILE * en passant:
#include <string.h> #include <stdio.h>
void f(FILE *f, const char *nom) { /* hop, on note quelque part qu'on joue avec le fichier f, par * exemple: */ mylog[log_i++] = strdup(nom); /* et on appelle la vraie fonction */ vraif(f, nom); }
(en gros)
Eh bien, pour ecrire cette fonction, je *suis oblige* d'inclure stdio.h, alors que je ne n'en ai rien a foutre du "vrai" sens de FILE *.
et il n'y a pas de solution "propre et normee" qui marche mieux...
In article <87bpldclt1.fsf@gauss.cs.tamu.edu>,
Gabriel Dos Reis <gdr@cs.tamu.edu> wrote:
Richard Delorme <abulmo@nospam.fr> writes:
| Le 14/09/2009 20:01, Marc Espie a écrit :
| > In article<4aae4785$0$12643$ba4acef3@news.orange.fr>,
| > Richard Delorme<abulmo@nospam.fr> wrote:
| >> Le 14/09/2009 14:56, Marc Espie a écrit :
| >>
| >>> dans tous les cas ou ils finissent par tomber sur des cas ou "ca serait
| >>> bien", j'essaie de leur expliquer que c'est un ECHEC de conception, ou le
| >>> developpeur n'a pas reussi a faire assez simple (et de mon point de vue,
| >>> on en trouve meme dans la bibliotheque standard, FILE * est une grosse
| >>> connerie, a mon avis).
| >>
| >> En quel sens FILE est une connerie ?
| >
| > Par exemple, ca te rend impossible de prototyper une fonction qui prend
| > un fichier ouvert en parametre sans inclure stdio.h...
| >
| > si c'est une fonction qui le manipule comme handle opaque, et qui se
contente
| > de le passer a une autre fonction, c'est tres cretin.
|
| Si j'ai bien compris, tu veux dire que si l'on avait, par exemple, un
| "struct file_t" au lieu de FILE, ça allégerait un peu certains
| codes. Pourquoi pas.
avons-nous des exemples de ces codes qui seraient allégés ?
Moi j'en ai deja eu sous la main, style une fonction qui prend un
FILE * en passant:
#include <string.h>
#include <stdio.h>
void
f(FILE *f, const char *nom)
{
/* hop, on note quelque part qu'on joue avec le fichier f, par
* exemple:
*/
mylog[log_i++] = strdup(nom);
/* et on appelle la vraie fonction */
vraif(f, nom);
}
(en gros)
Eh bien, pour ecrire cette fonction, je *suis oblige* d'inclure stdio.h,
alors que je ne n'en ai rien a foutre du "vrai" sens de FILE *.
et il n'y a pas de solution "propre et normee" qui marche mieux...
| Le 14/09/2009 20:01, Marc Espie a écrit : | > In article<4aae4785$0$12643$, | > Richard Delorme wrote: | >> Le 14/09/2009 14:56, Marc Espie a écrit : | >> | >>> dans tous les cas ou ils finissent par tomber sur des cas ou "ca serait | >>> bien", j'essaie de leur expliquer que c'est un ECHEC de conception, ou le | >>> developpeur n'a pas reussi a faire assez simple (et de mon point de vue, | >>> on en trouve meme dans la bibliotheque standard, FILE * est une grosse | >>> connerie, a mon avis). | >> | >> En quel sens FILE est une connerie ? | > | > Par exemple, ca te rend impossible de prototyper une fonction qui prend | > un fichier ouvert en parametre sans inclure stdio.h... | > | > si c'est une fonction qui le manipule comme handle opaque, et qui se contente | > de le passer a une autre fonction, c'est tres cretin. | | Si j'ai bien compris, tu veux dire que si l'on avait, par exemple, un | "struct file_t" au lieu de FILE, ça allégerait un peu certains | codes. Pourquoi pas.
avons-nous des exemples de ces codes qui seraient allégés ?
Moi j'en ai deja eu sous la main, style une fonction qui prend un FILE * en passant:
#include <string.h> #include <stdio.h>
void f(FILE *f, const char *nom) { /* hop, on note quelque part qu'on joue avec le fichier f, par * exemple: */ mylog[log_i++] = strdup(nom); /* et on appelle la vraie fonction */ vraif(f, nom); }
(en gros)
Eh bien, pour ecrire cette fonction, je *suis oblige* d'inclure stdio.h, alors que je ne n'en ai rien a foutre du "vrai" sens de FILE *.
et il n'y a pas de solution "propre et normee" qui marche mieux...
espie
In article , Gabriel Dos Reis wrote:
(Marc Espie) writes:
| In article <4aae4785$0$12643$, | Richard Delorme wrote: | >Le 14/09/2009 14:56, Marc Espie a écrit : | > | >> dans tous les cas ou ils finissent par tomber sur des cas ou "ca serait | >> bien", j'essaie de leur expliquer que c'est un ECHEC de conception, ou le | >> developpeur n'a pas reussi a faire assez simple (et de mon point de vue, | >> on en trouve meme dans la bibliotheque standard, FILE * est une grosse | >> connerie, a mon avis). | > | >En quel sens FILE est une connerie ? | | Par exemple, ca te rend impossible de prototyper une fonction qui prend | un fichier ouvert en parametre sans inclure stdio.h...
Et pourquoi ne voudrais-tu pas inclure <stdio.h> si ta fonction prétend prendre des fichiers ouverts ?
| si c'est une fonction qui le manipule comme handle opaque, et qui se contente | de le passer a une autre fonction, c'est tres cretin.
Non. C'est essayer de duplication de l'information qu'on ne métrise pas qui est nocif.
Attend, je te parle de passer un parametre a travers une fonction, il ne s'agit pas de dupliquer quoi que ce soit. C'est un idiome de style:
void f(T a, T b, FILE *c) { /* je fais des trucs avec a et b */ /* g, elle, utilisera c */ g(a, b, c); }
sauf semantique invraisemblable, j'ai generalement le droit de faire ce genre de chose, et pas de necessite imperieuse de savoir ce qui se cache derriere c...
... mais je dois inclure <stdio.h> pour que ca fonctionne...
In article <87hbv5clza.fsf@gauss.cs.tamu.edu>,
Gabriel Dos Reis <gdr@cs.tamu.edu> wrote:
espie@lain.home (Marc Espie) writes:
| In article <4aae4785$0$12643$ba4acef3@news.orange.fr>,
| Richard Delorme <abulmo@nospam.fr> wrote:
| >Le 14/09/2009 14:56, Marc Espie a écrit :
| >
| >> dans tous les cas ou ils finissent par tomber sur des cas ou "ca serait
| >> bien", j'essaie de leur expliquer que c'est un ECHEC de conception, ou le
| >> developpeur n'a pas reussi a faire assez simple (et de mon point de vue,
| >> on en trouve meme dans la bibliotheque standard, FILE * est une grosse
| >> connerie, a mon avis).
| >
| >En quel sens FILE est une connerie ?
|
| Par exemple, ca te rend impossible de prototyper une fonction qui prend
| un fichier ouvert en parametre sans inclure stdio.h...
Et pourquoi ne voudrais-tu pas inclure <stdio.h> si ta fonction prétend
prendre des fichiers ouverts ?
| si c'est une fonction qui le manipule comme handle opaque, et qui se contente
| de le passer a une autre fonction, c'est tres cretin.
Non. C'est essayer de duplication de l'information qu'on ne métrise pas
qui est nocif.
Attend, je te parle de passer un parametre a travers une fonction, il ne
s'agit pas de dupliquer quoi que ce soit. C'est un idiome de style:
void
f(T a, T b, FILE *c)
{
/* je fais des trucs avec a et b */
/* g, elle, utilisera c */
g(a, b, c);
}
sauf semantique invraisemblable, j'ai generalement le droit de faire ce
genre de chose, et pas de necessite imperieuse de savoir ce qui se cache
derriere c...
... mais je dois inclure <stdio.h> pour que ca fonctionne...
| In article <4aae4785$0$12643$, | Richard Delorme wrote: | >Le 14/09/2009 14:56, Marc Espie a écrit : | > | >> dans tous les cas ou ils finissent par tomber sur des cas ou "ca serait | >> bien", j'essaie de leur expliquer que c'est un ECHEC de conception, ou le | >> developpeur n'a pas reussi a faire assez simple (et de mon point de vue, | >> on en trouve meme dans la bibliotheque standard, FILE * est une grosse | >> connerie, a mon avis). | > | >En quel sens FILE est une connerie ? | | Par exemple, ca te rend impossible de prototyper une fonction qui prend | un fichier ouvert en parametre sans inclure stdio.h...
Et pourquoi ne voudrais-tu pas inclure <stdio.h> si ta fonction prétend prendre des fichiers ouverts ?
| si c'est une fonction qui le manipule comme handle opaque, et qui se contente | de le passer a une autre fonction, c'est tres cretin.
Non. C'est essayer de duplication de l'information qu'on ne métrise pas qui est nocif.
Attend, je te parle de passer un parametre a travers une fonction, il ne s'agit pas de dupliquer quoi que ce soit. C'est un idiome de style:
void f(T a, T b, FILE *c) { /* je fais des trucs avec a et b */ /* g, elle, utilisera c */ g(a, b, c); }
sauf semantique invraisemblable, j'ai generalement le droit de faire ce genre de chose, et pas de necessite imperieuse de savoir ce qui se cache derriere c...
... mais je dois inclure <stdio.h> pour que ca fonctionne...
| d'expliquer aux etudiants comment ca se debuggue, et pourquoi c'est un | outil extremement puissant (et donc passablement dangereux), alors, oui, | ca vaut le coup.
Un type abstrait, ça se debogue pas :-)
| Pour ma pomme, je vois plus de conneries resultant de l'usage immodere de | typedef que d'usages judicieux: je prefere dire que non, il vaut mieux ne | pas s'en servir *sauf excellentes raisons* (qui sont, essentiellement, | une tres bonne maitrise de la notion de type abstrait et de portabilite).
| d'expliquer aux etudiants comment ca se debuggue, et pourquoi c'est un
| outil extremement puissant (et donc passablement dangereux), alors, oui,
| ca vaut le coup.
Un type abstrait, ça se debogue pas :-)
| Pour ma pomme, je vois plus de conneries resultant de l'usage immodere de
| typedef que d'usages judicieux: je prefere dire que non, il vaut mieux ne
| pas s'en servir *sauf excellentes raisons* (qui sont, essentiellement,
| une tres bonne maitrise de la notion de type abstrait et de portabilite).
| d'expliquer aux etudiants comment ca se debuggue, et pourquoi c'est un | outil extremement puissant (et donc passablement dangereux), alors, oui, | ca vaut le coup.
Un type abstrait, ça se debogue pas :-)
| Pour ma pomme, je vois plus de conneries resultant de l'usage immodere de | typedef que d'usages judicieux: je prefere dire que non, il vaut mieux ne | pas s'en servir *sauf excellentes raisons* (qui sont, essentiellement, | une tres bonne maitrise de la notion de type abstrait et de portabilite).
Tu veux pouvoir dupliquer la signification de « FILE* »
| C'est un idiome de style: | | void | f(T a, T b, FILE *c) | { | /* je fais des trucs avec a et b */ | /* g, elle, utilisera c */ | g(a, b, c); | } | | sauf semantique invraisemblable, j'ai generalement le droit de faire ce | genre de chose, et pas de necessite imperieuse de savoir ce qui se cache | derriere c... | | ... mais je dois inclure <stdio.h> pour que ca fonctionne...
Tu veux pouvoir dupliquer la signification de « FILE* »
| C'est un idiome de style:
|
| void
| f(T a, T b, FILE *c)
| {
| /* je fais des trucs avec a et b */
| /* g, elle, utilisera c */
| g(a, b, c);
| }
|
| sauf semantique invraisemblable, j'ai generalement le droit de faire ce
| genre de chose, et pas de necessite imperieuse de savoir ce qui se cache
| derriere c...
|
| ... mais je dois inclure <stdio.h> pour que ca fonctionne...
Tu veux pouvoir dupliquer la signification de « FILE* »
| C'est un idiome de style: | | void | f(T a, T b, FILE *c) | { | /* je fais des trucs avec a et b */ | /* g, elle, utilisera c */ | g(a, b, c); | } | | sauf semantique invraisemblable, j'ai generalement le droit de faire ce | genre de chose, et pas de necessite imperieuse de savoir ce qui se cache | derriere c... | | ... mais je dois inclure <stdio.h> pour que ca fonctionne...
C'est vrai que les types pointeurs sur fonction facilitent la lecture, sans typedef ;)
Si on arrive à faire comprendre les typedefs pour des fonctions, la syntaxe de déclaration des pointeurs doit moins perturber ensuite. Non, ce n'est pas une suggestion sur l'ordre dans lequel enseigner ces choses :-)
Je me demande si : typedef int *int_ptr; int_ptr p; aiderait à expliquer (séparer l'aspect description du type de la déclaration de variable). Peut-être pas.
Je n'en suis pas sûr, mais il me semble bien qu'il y a un truc du genre déclarer une fonction de tel ou tel type qu'on ne peut pas faire sans typedef.
En C++ c'est nécessaire pour déclarer une fonction qui prend en argument une fonction de linkage différent (ça ne concerne pas g++ qui ne prend pas en compte le linkage dans le typage), mais en C j'ai plus de mal à voir.
Pierre Maurette wrote:
Mickaël Wolff, le 14/09/2009 a écrit :
C'est vrai que les types pointeurs sur fonction facilitent la lecture,
sans typedef ;)
Si on arrive à faire comprendre les typedefs pour des fonctions, la
syntaxe de déclaration des pointeurs doit moins perturber ensuite. Non,
ce n'est pas une suggestion sur l'ordre dans lequel enseigner ces choses
:-)
Je me demande si :
typedef int *int_ptr;
int_ptr p;
aiderait à expliquer (séparer l'aspect description du type de la
déclaration de variable). Peut-être pas.
Je n'en suis pas sûr, mais il me semble bien qu'il y a un truc du genre
déclarer une fonction de tel ou tel type qu'on ne peut pas faire sans
typedef.
En C++ c'est nécessaire pour déclarer une fonction qui prend en argument
une fonction de linkage différent (ça ne concerne pas g++ qui ne prend
pas en compte le linkage dans le typage), mais en C j'ai plus de mal à
voir.
C'est vrai que les types pointeurs sur fonction facilitent la lecture, sans typedef ;)
Si on arrive à faire comprendre les typedefs pour des fonctions, la syntaxe de déclaration des pointeurs doit moins perturber ensuite. Non, ce n'est pas une suggestion sur l'ordre dans lequel enseigner ces choses :-)
Je me demande si : typedef int *int_ptr; int_ptr p; aiderait à expliquer (séparer l'aspect description du type de la déclaration de variable). Peut-être pas.
Je n'en suis pas sûr, mais il me semble bien qu'il y a un truc du genre déclarer une fonction de tel ou tel type qu'on ne peut pas faire sans typedef.
En C++ c'est nécessaire pour déclarer une fonction qui prend en argument une fonction de linkage différent (ça ne concerne pas g++ qui ne prend pas en compte le linkage dans le typage), mais en C j'ai plus de mal à voir.
"Francois" a écrit dans le message de news: 4aae9170$0$30959$
Dans "a = *p;" on fait comme si *p était une variable de type int. Dans "*p = 30;", pareil. Après, la variable *p n'a pas la même signification (valeur ou zone mémoire) suivant qu'elle est à droite ou à gauche du symbole "=", mais cette nuance, finalement, on la retrouve absolument à l'identique avec une variable dite "classique" : dans "var = 30;" et "x = var;", var n'a pas la même signification (valeur ou zone mémoire).
tiens j'avais jamais vu ça comme ça...
mais quand tu as déclaré f( int *p)
et qu'il faut l'appeler par f( &a )
ça ne colle plus avec ta representation mentale des pointeurs...
moi mon premier bouquin (un vague manuel de turbo C) parlait d'opérateur "contenu de"... et ça m'est resté... comme quoi le premier bouquin compte vachement...
"Francois" <francois@noSpam.fr> a écrit dans le message de news:
4aae9170$0$30959$426a74cc@news.free.fr...
Dans "a = *p;" on fait comme si *p était une variable de type int. Dans
"*p = 30;", pareil. Après, la variable *p n'a pas la même signification
(valeur ou zone mémoire) suivant qu'elle est à droite ou à gauche du
symbole "=", mais cette nuance, finalement, on la retrouve absolument à
l'identique avec une variable dite "classique" : dans "var = 30;" et "x =
var;", var n'a pas la même signification (valeur ou zone mémoire).
tiens j'avais jamais vu ça comme ça...
mais quand tu as déclaré f( int *p)
et qu'il faut l'appeler par f( &a )
ça ne colle plus avec ta representation
mentale des pointeurs...
moi mon premier bouquin (un vague manuel
de turbo C) parlait d'opérateur "contenu de"...
et ça m'est resté... comme quoi le premier bouquin
compte vachement...
"Francois" a écrit dans le message de news: 4aae9170$0$30959$
Dans "a = *p;" on fait comme si *p était une variable de type int. Dans "*p = 30;", pareil. Après, la variable *p n'a pas la même signification (valeur ou zone mémoire) suivant qu'elle est à droite ou à gauche du symbole "=", mais cette nuance, finalement, on la retrouve absolument à l'identique avec une variable dite "classique" : dans "var = 30;" et "x = var;", var n'a pas la même signification (valeur ou zone mémoire).
tiens j'avais jamais vu ça comme ça...
mais quand tu as déclaré f( int *p)
et qu'il faut l'appeler par f( &a )
ça ne colle plus avec ta representation mentale des pointeurs...
moi mon premier bouquin (un vague manuel de turbo C) parlait d'opérateur "contenu de"... et ça m'est resté... comme quoi le premier bouquin compte vachement...
Stephane Legras-Decussy
"Gabriel Dos Reis" a écrit dans le message de news:
Tu peux comparer les deux declarations de signal : celle qui utilise un typedef judicieux, et l'autre qui n'utilise pas de typedef du tout.
je vois bien ce que tu veux dire...
mais d'un autre côté j'aime bien que quelque chose de compliqué ait une écriture compliquée...
on n'est pas "pris en traitre"...
c'est en partie pour ça que j'aime pas C++...l'idée de surcharger un opérateur me fait frémir...
"Gabriel Dos Reis" <gdr@cs.tamu.edu> a écrit dans le message de news:
877hw1e16t.fsf@gauss.cs.tamu.edu...
Tu peux comparer les deux declarations de signal : celle qui utilise un
typedef judicieux, et l'autre qui n'utilise pas de typedef du tout.
je vois bien ce que tu veux dire...
mais d'un autre côté j'aime bien que
quelque chose de compliqué ait une
écriture compliquée...
on n'est pas "pris en traitre"...
c'est en partie pour ça que j'aime
pas C++...l'idée de surcharger un opérateur
me fait frémir...