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
ld
On 14 sep, 20:00, (Marc Espie) wrote:
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,



le C possede 5 espaces de noms. Il peut etre dangeureux ou avantageux
de jouer avec cet aspect du langage, ca depend du contexte.

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.



Le preprocesseur est bien souvent le bouc emissaire d'un mal plus
profond.

OUI, ce sont tous des choses qui ne sont plus tres vraies en C++ avec un
usage correct des namespace...



Qui sont aussi controverses, meme par certains experts C++.

Dans les deux cas, c'est une question de pratique.

a+, ld.
Avatar
Pierre Maurette
Mickaël Wolff, le 14/09/2009 a écrit :
Stephane Legras-Decussy wrote:
"Pierre Maurette" a écrit dans le message de
news:
. 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...


C'est vrai que les types pointeurs sur fonction facilitent la lecture,
sans typedef ;)



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.
Je ne sais pas s'il y a une autre solution, je n'en vois pas, mais je
l'utilise pour les définitions de structures croisées (problème
déclaration forward).

Et puis je trouve bien pratique de sérier les trucs, genre:

typedef uint8_t pixelRVB[3];
/*
typedef uint8_t pixelRVBpadding[4];
*/

typedef pixelRVB image1024_768[1024][768];

#define FPS 50
#define TIME 20
#define NB_IMAGES TIME * FPS

image1024_768 sequence[NB_IMAGES];

etc.

--
Pierre Maurette
Avatar
candide
Manuel Pégourié-Gonnard a écrit :

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 dirais qu'il n'y a qu'un seul opérateur *, l'opérateur de déréférencement,
d'ailleurs la Norme donne la liste des opérateurs et leur syntaxe.

IMHO quand on écrit

int *p= NULL;

* n'est pas un opérateur, c'est un élément d'une déclaration, de même que n'est pas l'opérateur d'affectation, pareil c'est un élément d'une déclaration
qui définit ce qu'on appelle l'initialisation de la déclaration. Declarations et
Expressions sont des parties distinctes de la Norme et les syntaxe sont bien
séparées. Bien sûr, la syntaxe des déclaration a été conçue pour être
expressive. Enfin, ce n'est que mon avis.
Avatar
Gabriel Dos Reis
(Marc Espie) writes:

| 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++.

J'écris souvent des programmes en C.

| Tu sais aussi bien que moi que les usages sont differents. ;-)

même en C++.

-- Gaby
Avatar
espie
In article ,
Pierre Maurette wrote:
Mickaël Wolff, le 14/09/2009 a écrit :
Stephane Legras-Decussy wrote:
"Pierre Maurette" a écrit dans le message de
news:
. 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...


C'est vrai que les types pointeurs sur fonction facilitent la lecture,
sans typedef ;)



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.
Je ne sais pas s'il y a une autre solution, je n'en vois pas, mais je
l'utilise pour les définitions de structures croisées (problème
déclaration forward).



Ca n'est pas necessaire.

T'as parfaitement le droit de faire
struct a;

struct b {
struct a *machin;
};

et assimiles.
Avatar
Gabriel Dos Reis
candide writes:

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

Non.

Mais cela ne correspond pas à la notion prosaïque « d'utiliser » -- je
sais pourquoi et comment un compilateur ne serait pas d'accord, mais
considère que tu essaies d'expliquer ce que c'est les pointeurs à un
public qui découvre le sujet, « &a » n'est pas une « utilisation »
jusque là connue.

-- Gaby
Avatar
Gabriel Dos Reis
Manuel Pégourié-Gonnard <mpg+ writes:

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

Pas juste « *p », mais la variable « p » tout court.
On peut utiliser « p » de manière autre que « *p » -- par exemple « p + 1 »

| 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".

OK.

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

La vraie raison de la syntaxe C, c'est qu'à l'époque (circa 1970),
certaines personnes trouvaient que la précédence d'opérateurs était une
idée brillantissime. Plus tard, d'autres personnes présentes dans la
salle UNIX diront que « the C syntax is an experience that has failed. »

-- Gaby
Avatar
Gabriel Dos Reis
Francois writes:

| Manuel Pégourié-Gonnard a écrit :
|
| > Je veux parler de l'opération qui donne accès au contenu sur lequel
| > pointe le pointeur. Par exemple dans "a = *p;" la variable "a" reçoit la
| > valeur pointée par "p", et non pas la valeur de "p" lui-même.
|
| D'accord, mais dans ce cas, j'ai dû mal à comprendre pourquoi tu dis
| qu'il y a deux opérateurs "*". Enfin, je comprends mais je ne trouve
| pas que ce soit la façon la plus simple de voir les choses.
|
| Pour moi, comme le disait Marc, je trouve plus simple de dire qu'avec
| "int *p;", *p représente une variable de type int (modulo une gestion
| de la mémoire différente c'est vrai).

Je n'ai jamais réussi à voir une explication simple des pointeurs, basée
sur la syntaxe tortueuse des déclarations C.

J'ose espérer que la notion (e.g. sémantique) de pointeur peut
s'acquerir indépendamment de la syntaxe. Autrement, on est foutu.

-- Gaby
Avatar
Gabriel Dos Reis
(Marc Espie) writes:

| 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*.

Je suis de l'avis contraire.

Il est indispensable qu'ils connaissent cette syntaxe très répandue dans
le monde C. Cependant, je crois que le plus simple garde-fou qu'on peut
leur donner, c'est qu'ils doivent impérativement respecter les types
variables -- sinon, ils s'exposent à de grosses colères de la part du
dragon, même si le langage paraît, en surface, laxiste. Selon DMR
« the C programming language is strongly typed but weakly checked. »

Dans cette optique, je trouve qu'il est plus simple de grouper les
types. La syntaxe C n'est pas suffisamment régulière ou simple pour
essayer d'expliquer des notions sémantiques sur des considérations purement
grammaticales.

| Ca ne correspond aux usages habituels. Lorsqu'ils vont tomber sur du vrai
| code, ils vont etre surpris.

Le « vrai » code C est beaucoup plus varié qu'on ne l'imagine souvent.

| Ils vont prendre des habitudes qui vont a
| l'encontre des usages industriels habituels.

Je crois que l'essentiel, c'est qu'ils savent qu'ils existent plusieurs
styles et que l'important c'est qu'ils adhèrent aux règles de codage du
projet. Pour enseigner à programmer en C, je crois qu'il est plus
efficace de faire passer effectivement la grande majorité des notions
lorsqu'on s'éloigne des arcanes de la syntaxe abscone C.

-- Gaby
Avatar
Gabriel Dos Reis
"Stephane Legras-Decussy" writes:

| "Pierre Maurette" a écrit dans le message de
| news:
| >. 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...

Un typedef mème à un type de base sert à exprimer un concept dans un
langage même pauvre (comme le C ou C++). On n'écrit pas un programme
juste pour la machine ou le compilateur. On écrit un programme pour
communiquer des idées à d'autres programmeurs -- e.g. des humains.

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.


-- Gaby