OVH Cloud OVH Cloud

Différence de résultat entre compilateurs

291 réponses
Avatar
YannicK
Bonjour,

é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,



--
YannicK
yann801 *arobase* yahoo *point* fr
yann801 *at* yahoo *dot* fr

10 réponses

Avatar
Pierre Maurette
Gabriel Dos Reis, le 14/09/2009 a écrit :
Richard Delorme writes:

Le 14/09/2009 18:42, Pierre Maurette a écrit :

Je me répète, mais je trouve que:

int a;
int* p;

est bien plus clair.





C'est ce que j'enseigne à mes élèves.

Moi je ne trouve pas.

Entre autre parce que :

int* p, a;

ne déclare pas deux pointeurs.



J'ai peu de temps à passer pour expliquer ces subtilités.
Je leur demande une déclaration à la fois -- en général, le code est
beaucoup plus clair ; je trouve.



D'autant qu'il y a un message à faire passer d'urgence si c'est
nécessaire, à savoir que compacter le code source n'optimise rien, bien
au contraire, c'est une mauvaise habitude. Et que le copier-coller, les
modèles, l'auto-completion, etc. ça existe.
Et un peu plus tard, expliquer que préparer un source pour un
refactoring sans outils spécifique peut faire gagner beaucoup de temps.

--
Pierre Maurette
Avatar
candide
Pierre Maurette a écrit :

int* p = NULL;
/* du code */
p = &a;

Je n'ai pas affecté de valeur à a avant de l'utiliser.





Et justement, c'est pas interdit ça ?
Avatar
Manuel Pégourié-Gonnard
Gabriel Dos Reis scripsit:

Manuel Pégourié-Gonnard <mpg+ writes:

| Marc Espie scripsit:
| > Bof, ca c'est pas un vrai souci, de mon point de vue. Ca depend comment
| > tu expliques. Pour moi, int *p, ca te dit que l'expression *p est de
| > type int. Et donc c'est le meme operateur.
|
| Hum. Il me semble qu'il y a quand même une grande différence entre
|
| int a;
| int *p;
|
| car dans le premier cas 'a' est effectivement un objet de type int que
| tu peux utiliser directement, alors que dans le deuxième cas, tu dois te
| farcir l'allocation de mémoire avant de pouvoir considérer que
| l'expression *p est un truc de type int valide.

Dans le premier cas ("int a;") tu dois affecter une valeur à "a"
avant de pouvoir l'utiliser. Dans le second cas ("int *p;"), tu dois
affecter une valeur à "p" avant de pouvoir l'utiliser.



Voilà, dans le deuxième cas c'est à "p" qu'on doit affecter une valeur
avant de pouvoir utiliser *p. Donc ça me paraît un peu raide de dire que
"int *p" c'est comme "int a" où on a remplacé "a" par "*p". Je ne peux
pas écrire "*p = 2;" juste après, alors que je pourrais écrire "a = 2;".
Donc on a bien déclaré un objet "p" de type "int *", et pas un objet
"*p" de type "int".

C'est ce qui me chifonne avec l'explication de Marc, citée en début de
message : pour moi, la conclusion n'est pas que c'est le même opérateur
(l'un sert à construire des types dérivés, l'autre à déréférencer) mais
que c'est compréhensible de vouloir utiliser la même notation pour ces
deux opérateurs différents.

--
Manuel Pégourié-Gonnard Institut de mathématiques de Jussieu
http://weblog.elzevir.fr/ http://people.math.jussieu.fr/~mpg/
Avatar
espie
In article ,
Gabriel Dos Reis wrote:
| - pas le droit aux fichiers d'entetes imbriques. Tout mettre a plat au
| depart)

pourquoi ?



parce que le C possede un seul espace de noms, et que j'ai passe bien trop
longtemps a me battre avec des trucs qui devraient compiler, mais qui ne
compilent pas, parce qu'ils redefinissent une macro au fond d'un entete
de bibliotheque, mais l'entete entre en conflit avec un autre entete.
Deja, quand c'est tout a plat au top-level, c'est pas simple. Quand en plus
c'est enferme au fond de trois entetes, c'est la croix et la banniere a
corriger.

Ca evite aussi les dependances "par paresse", style on met tout dans un
fichier d'entetes, ou les dependances fortuites (pas la peine d'inclure
string.h parce qu'il y a deja une bibliotheque du programme qui s'en sert).

OUI, ce sont tous des choses qui ne sont plus tres vraies en C++ avec un
usage correct des namespace...
Avatar
espie
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.

(c'est exactement la raison qui fait que C++ a un iosfwd)
Avatar
espie
In article ,
Gabriel Dos Reis wrote:
Richard Delorme writes:

| Le 14/09/2009 18:42, Pierre Maurette a écrit :
| >
| > Je me répète, mais je trouve que:
| >
| > int a;
| > int* p;
| >
| > est bien plus clair.

C'est ce que j'enseigne à mes élèves.



Oui, mais toi tu fais du C++.
Tu sais aussi bien que moi que les usages sont differents. ;-)
Avatar
espie
In article ,
Manuel Pégourié-Gonnard <mpg+ wrote:
C'est ce qui me chifonne avec l'explication de Marc, citée en début de
message : pour moi, la conclusion n'est pas que c'est le même opérateur
(l'un sert à construire des types dérivés, l'autre à déréférencer) mais
que c'est compréhensible de vouloir utiliser la même notation pour ces
deux opérateurs différents.



Confere message de moi il y a quelques dizaines de message plus haut: ce
qui pose probleme, ce ne sont pas les pointeurs, mais bien la gestion de
la memoire.

Je ne vois aucune difficulte dans la declaration
int *p;

ce qu'on fait de p, en particulier le fait que c'est un pointeur qui ne
pointe nulle part, pour l'instant, c'est la qu'est toute la difficulte.

L'allocation de la memoire, et le moment ou on rend la memoire au systeme,
c'est la qu'on rigole. Et c'est la qu'il faut des exemples tres precis assez
vite pour eviter les problemes...

et de preference, apres avoir vu les tableaux, histoire de pouvoir donner
rapidement des exemples simples qui servent a quelque chose, comme l'allocation
dynamique de tableau.

Parce que des trucs genre
int *p;

p = malloc(sizeof(int));

...
*p = 42;

...

free(p);

c'est quand meme de l'enculage de mouches, c'est artificiel, et ca ne sert
a rien en tant que tel...
Avatar
espie
In article ,
Pierre Maurette wrote:
Bien entendu le problème est que sans typedef le int* p contient un
piège:
int* p, q, r;

Mais je préfère ce dommage collatéral à l'écriture int *p pour déclarer
p comme pointeur vers int. On va éventuellement édicter la règle de
style de ne déclarer qu'un pointeur par ligne, ou de passer par un
typedef.



J'ai repondu a Gaby tongue-in-cheek que c'etait un usage C++.

Je vais preciser: c'est a mon avis NOCIF d'enseigner aux etudiants d'ecrire
int* p; pour declarer un pointeur *EN C*.

Ca ne correspond aux usages habituels. Lorsqu'ils vont tomber sur du vrai
code, ils vont etre surpris. Ils vont prendre des habitudes qui vont a
l'encontre des usages industriels habituels.

Oui, ca se discute de savoir si la tradition est mieux ou pas. Mais bon,
si je forme des programmeurs C, je ne vais pas commencer a foutre le bordel
en leur apprenant a faire du C++....
Avatar
Francois
Manuel Pégourié-Gonnard a écrit :

C'est ce qui me chifonne avec l'explication de Marc, citée en début de
message : pour moi, la conclusion n'est pas que c'est le même opérateur
(l'un sert à construire des types dérivés, l'autre à déréférencer) mais
que c'est compréhensible de vouloir utiliser la même notation pour ces
deux opérateurs différents.



Je ne comprends le "déréférencer" ?
Construire des "types dérivées", j'imagine que c'est pour
int *p; mais je ne comprends pas l'expression "déréférencer"
dans ce que tu as dit.


--
François Lafont
Avatar
Pierre Maurette
Gabriel Dos Reis, le 14/09/2009 a écrit :
Pierre Maurette writes:



[...]

int a;
int* p = NULL;
/* du code */
p = &a;

Je n'ai pas affecté de valeur à a avant de l'utiliser.



Nous devons avoir des notions différentes de « utiliser ». La mienne est
beaucoup plus prosaïque, proche du programmeur débutant qui se pose la
question à laquelle je répondait -- en Standardais « &a » ne demande pas
une conversion de « lvalue » en « non-lvalue. »



J'ai depuis longtemps eu l'occasion d'apprécier votre sens de l'humour.

--
Pierre Maurette