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
-ed-
On 14 sep, 14:04, candide wrote:
Il me semble que ce n'est pas le plus courant que l'on rencontre. D'aille urs, je
trouve que le mot "variable" est très trompeur. Le cas que j'ai en mé moire (!)
est le suivant :

int *remplirMal(int n)
{
  int t[100] = { 0 };
  int i;

  for (i = 0; i < n; i++)
    t[i] = i;
  return t;

}

Au point que je n'osais plus faire renvoyer de pointeur à une fonction. Il faut



Ce code est erroné, on est bien d'accord ?

bien comprendre qu'il y a plein de situations où on peut renvoyer un po inteur
vers quelque chose qui "ressemble" à une variable locale (typiquement s trchr())



Ah ? Évidemment, si on ne sait pas que le paramètre est un pointeur,
on fini par dire n'importe quoi ...

et c'est pas du tout évident de discerner les différentes situations quand on
est débutant et même débutant avancé. Et puis tu as la situation de la mémoire



Si on sait clairement expliquer la différence entre une valeur, une
adresse, une variable locale, un paramètre, un pointeur, tout devient
clair. Si on prétend ne pas expliquer ces notions sous prétexte que
"c'est trop difficile" (les étudiants ne sont pas tous des abrutis;
merci pour eux), c'est la confusion assurée.

allouée. D'ailleurs, c'est en analysant tout cela que j'ai compris que le mot
variable est un mot qui est source de beaucoup de confusion. Le bon mot e st le



C'est le mot courant utilisé en programmation 'générale'. Une variabl e
est tout simplement un emplacement mémoire contenant une valeur. C'est
pas compliqué.

mot "objet", c'est un mot qui fait peur (comme le mot "identificateur") m ais



Le terme 'objet' est très flou ...

c'est surtout parce qu'il est expliqué de manière abstraite, non inst anciée.
D'une façon générale, les exposés, in vivo ou livresques, sont be aucoup trop
verbeux et abstraits et dénués d'exemples _bien choisis_ (parce que d es exemples
qui obscurcissent, ça oui, on en trouve).



Ce qui est bien, c'est toi, tu n'es pas 'verbeux' !

Ce n'est pas le problème de la copie, c'est le problème du désir de coder.
strcmp ne donne pas envie de coder (à moi, oui, à beaucoup d'étudia nts, non ou
pas présenté tel quel).



Il faut présenter les fonctions comme un mécanisme permettant de
simplifier le codage et le faire 'en situation'. Dans un premier
temps, tu leur demandes de copier une chaine 'directement' dans le main
(), puis, tu vérifies qu'ils ont bien utilisé une boucle, le 0 final
etc., et enfin tu leur demandes faire une fonction qui fait le boulot
une bonne fois pour toutes. C'est pas difficile, et l'intérêt
pédagogique est évident...

Les questions liées à l'interface seront résolues en rappelant les
passages de paramètres par valeur, la nécessité de passer l'adresse d u
tableau de char etc. Un étudiant de L3 est capable de penser par lui-
même et de trouver des solutions ou alors c'est à désespérer du
système éducatif français... Si le niveau est si bas, aucune méthod e
pédagogique ne résoudra le problème...
Avatar
Gabriel Dos Reis
(Marc Espie) writes:

| In article <h8o2a1$9a6$,
| Marc Boyer wrote:
| >Le 14-09-2009, Gabriel Dos Reis a écrit :
| >> Je trouve que
| >>
| >> struct mpz_internal {
| >> // ...
| >> };
| >>
| >> typedef struct mpz_internal mpz_t[1];
| >>
| >> permet d'écrire des fonctions qui simulent très bien le passage par
| >> réference const, e.e.
| >>
| >> mpz_t mpz_negate(const mpz_t);
| >>
| >> (et cela marche presque très bien pour des composantes
| >> qui sont à l'intersection de C ou C++).
| >
| > Oui, c'est joli, mais est-ce bien recommandable ?
| >Tout variable est un tableau de taille 1. Mais est-ce
| >vraiment raisonnable ?
|
| Vu le nom choisi dans l'exemple, qui n'est pas tres anodin, non ca n'est
| pas issu d'un logiciel tres recommendable. ;-)

Et practiquement tout le monde l'utilise -- y compris les systèmes de
calcul scientifique les plus avancés. Parmi la floppée de logiciels
du même genre, c'est probablement le seul dont l'auteur fait un effort
constant de simplicité et de portabilité, malgré la technicité du sujet.

Mais c'est vrai qu'il fait beaucoup d'ombre à certains précurseurs nés
coté Ouest :-)

-- Gaby
Avatar
-ed-
On 14 sep, 14:54, candide wrote:
> La notion d'undefined behavior est tres
> difficile a integrer.

Personnellement, je n'ai pas encore vraiment bien compris ce que c'étai t. Oui,



C'est un comportement donc les conséquences sont imprévisibles.
Exemple trivial :

#include <stdio.h>

int main (void)
{
int x;

printf ("x = %dn", x);

return 0;
}

Personne ne peut prévoir ce que va afficher ce programme. Le
comportement est indéfini.

Je les comprends un peu. Savent pas utiliser des alias ?



ou plutôt un script ou mieux un makefile...
Avatar
-ed-
On 14 sep, 19:38, Pierre Maurette wrote:
> 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.  Cette
> affectation peut invoquer une allocation de mémoire ou non.
> Dans les deux cas, tu dois affecter une valeur à la variable avant de
> pouvoir l'utiliser.

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

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



Arrête de jouer à l'andouille...

Tu n'as pas utilisé a, mais l'adresse de a (&a) qui est définie du
moment que l'objet a est instancié.
Avatar
-ed-
On 14 sep, 19:57, candide wrote:
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 ?



Aie, aie aie... Y'a encore du boulot...

Évidemment que non ce n'est pas interdit. La valeur &a est
parfaitement définie (si a a été déclarée au préalable, ce qu'o n ne
voit plus ici...)...
Avatar
-ed-
On 14 sep, 19:59, Manuel Pégourié-Gonnard <mpg+ wrote:
C'est ce qui me chifonne avec l'explication de Marc, citée en début d e
message : pour moi, la conclusion n'est pas que c'est le même opérate ur
(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 ce s
deux opérateurs différents.



Ce qu'on peut reprocher au C, c'est que parfois, le même symbole (*
ou &, par exemple) peut servir à des usages différents. C'est sans
doute dû à un choix délibéré des concepteurs d'utiliser des symbo les
autres que des lettres pour définir les opérateurs... Peu importe,
c'est un fait qu'il faut intégrer, même si il dérange. En principe, i l
n'y a pas pas d'ambiguïté (si il y en avait, le compilateur ne saurait
pas quoi faire) .

Le cas extrême est quand même * qui a 3 significations :

- opérateur de multiplication
- déclaration ''un pointeur
- déréférencement d'un pointeur

Pour les pointeurs, Pascal utilise ^, ce qui fait que 2 usages
(déclaration et déréférencement).
Avatar
Pierre Maurette
-ed-, le 15/09/2009 a écrit :
On 14 sep, 19:38, Pierre Maurette wrote:
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.  Cette
affectation peut invoquer une allocation de mémoire ou non.
Dans les deux cas, tu dois affecter une valeur à la variable avant de
pouvoir l'utiliser.



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

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



Arrête de jouer à l'andouille...



Vois pas pourquoi y'aurait que moi qui n'aurait paqs droit de
participer au concours de clowns, hein.

Tu n'as pas utilisé a, mais l'adresse de a (&a) qui est définie du
moment que l'objet a est instancié.



Tautologie, puisqu'on peut définir l'instanciation d'un objet par le
fait de lui réserver une adresse. Une adresse typée, ou sizofée, si
vous acceptez l'expression. En C, langage de heut niveau, le fait de
prendre l'adresse d'une variable force son instanciation effective.
Sinon, si elle n'estg pas utilisée, elle peut ne jamais exister. Et
même utilisée elle peut avoir juste un tout petit bout d'existence
tapie dans un registre, sans inxstanciation donc. Il me semble
d'ailleurs que la norme interdit de prendre l'adresse d'une variable
qualifiée register.


--
Pierre Maurette
Avatar
-ed-
On 14 sep, 20:01, (Marc Espie) wrote:
>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...



Ce qui me parait être de bon sens. Comment utiliser un type qui
n'aurait pas été défini ?

si c'est une fonction qui le manipule comme handle opaque, et qui se cont ente
de le passer a une autre fonction, c'est tres cretin.



Techniquement il est très rare que FILE soit un véritable type opaque,
car pour implémenter les macros getc()et putc(), on a besoin des
éléments de la structure...
Avatar
-ed-
On 14 sep, 20:15, Pierre Maurette wrote:

int a; /* -ed- remis en place, sinon, on ne sait pas de quoi on
parle ... */

>> 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 ?

Non, il ne me semble pas. En revanche prendre l'adresse d'une variable
change son statut, d'une certaine façon.



Quel statut a été changé ? Pour moi, 'a' est une variable (ou un
objet, ça fait plus chic, il parait) qui n'a pas été modifiée et do nt
le contenu n'est pas défini. Son adresse, en revanche est parfaitement
définie et rien ne s'oppose à l'utiliser. C'est l'adresse de a qui a
été utilisée et non 'a' (c'est à dire son contenu encore appelé
valeur, car le nom de la variable et sa valeur sont confondus).
Avatar
-ed-
On 14 sep, 20:32, "Stephane Legras-Decussy"
wrote:
"Pierre Maurette" a écrit dans le message d enews: mn.73da7d994f4c3f2b.79__BEGIN_MASK_n#9g02mG7!__...__END_MASK_i?a63jf AD$

>. On va éventuellement édicter la règle de style de ne déclarer qu'un
>pointeur par ligne, ou de passer par un typedef.

pour moi le typedef c'est exclusivement
pour cacher struct, sinon c'est de l'obfuscation...



Je dirais que pour les structures, ce n'est pas indispensable. Par
contre, je suis pour son usage pour les pointeurs de fonctions, Ca
allège considérablement l'écriture. Tu connais le prototype de signal
() ?

dans tous les cas, je recommande un usage clair et bien défini d'un
suffixe qui rappelle de quoi on parle...

http://www.bien-programmer.fr/codage.php#conventions_nommage

je pense qu'on insiste pas assez sur l'importance du nommage...