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
Marc
Gabriel Dos Reis wrote:

Marc writes:

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

Que penses-tu de

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

?



À quel sens ? Comparé à :
void (*signal(int signum, void (*handler)(int)))(int);
?

En effet c'est un bon exemple montrant que les typedefs aident à la
lisibilité. Et comme mon message précédent était en faveur des typedefs,
j'approuve :-)
Avatar
Richard Delorme
Le 14/09/2009 23:04, Gabriel Dos Reis a écrit :


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

Comment ce code serait-il allégé sans l'inclusion de<stdio.h> ?



Ce qui serait allégé est le temps de compilation.
On peut légitimement penser que :

struct file_t;

void f(T a, T b, struct file_t *c)
{
/* ... */
g(a, b, c);
}

va compiler plus vite qu'une version incluant <stdio.h>, qui contient
quand même, chez moi (linux), près de 1000 lignes de codes, et
l'inclusion de plusieurs autres en-têtes.

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

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

Ahem.

-- Gaby
Avatar
Gabriel Dos Reis
Richard Delorme writes:

| Le 14/09/2009 23:04, Gabriel Dos Reis a écrit :
|
| >
| > | 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...
| >
| > Comment ce code serait-il allégé sans l'inclusion de<stdio.h> ?
|
| Ce qui serait allégé est le temps de compilation.

Maintenant, nous ne parlons plus de code allégé, mais de la lenteur d'un
certain compilateur sur un certain système.

| On peut légitimement penser que :
|
| struct file_t;

Pour moi, l'abstraction derrière « FILE* » n'est pas sous le control de
l'utilisateur, et ce dernier n'a aucune raison de vouloir la dupliquer.

Si on a mesuré que l'inclusion de <stdio.h> est *réellement* un
facteur déterminant dans un projet, alors on devrait légitement
demander aux auteurs du dit compilateur de s'occuper de la performance
du compilateur -- car cela m'étonnerait que le goulot d'étranglement
soit pour <stdio.h> et nettement moins pour d'autres combinaisons
d'entêtes, et ceci de manière déterminante pour le projet.

|
| void f(T a, T b, struct file_t *c)
| {
| /* ... */
| g(a, b, c);
| }
|
| va compiler plus vite qu'une version incluant <stdio.h>, qui contient
| quand même, chez moi (linux), près de 1000 lignes de codes, et
| l'inclusion de plusieurs autres en-têtes.

Je n'ai pas de mal à _fabriquer_ des exemples où je peux mesurer des
différences de quelques (milli)secondes -- e.g. testsuites.
Je voudrais voir des exemples pratiques de logiciels du monde réel.

-- Gaby
Avatar
Jean-Marc Bourguet
(Marc Espie) writes:

Difference d'usage. Comme je porte souvent du code ecrit ailleurs, les
fichiers d'entete imbriques me causent plus souvent des migraines que ceux
des projets plus simples... les projets gnu etant generalement
particulierement gratines, d'ailleurs, cote horreurs qui ne compilent pas
trop en dehors de linux, qu'on ne sait pas trop pourquoi au depart...



Entre des entêtes imbriqués et des entêtes non autosuffisants, je sais ce
que je prefère. Ce n'est pas les entêtes non autosuffisants.

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Richard Delorme
Le 15/09/2009 08:50, Gabriel Dos Reis a écrit :
Richard Delorme writes:

| Le 14/09/2009 23:04, Gabriel Dos Reis a écrit :
|
|>
|> | 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...
|>
|> Comment ce code serait-il allégé sans l'inclusion de<stdio.h> ?
|
| Ce qui serait allégé est le temps de compilation.

Maintenant, nous ne parlons plus de code allégé, mais de la lenteur d'un
certain compilateur sur un certain système.



Pour un compilateur donné, moins il y a de code, plus ça compile vite.

| On peut légitimement penser que :
|
| struct file_t;

Pour moi, l'abstraction derrière « FILE* » n'est pas sous le control de
l'utilisateur, et ce dernier n'a aucune raison de vouloir la dupliquer.



file_t pourrait rester une structure opaque, ce qui en ferait un type
abstrait non contrôlable par l'utilisateur. Bref ça changerait peu la
situation actuelle, sauf la possibilité d'éviter l'inclusion de <stdio.h>

Si on a mesuré que l'inclusion de<stdio.h> est *réellement* un
facteur déterminant dans un projet, alors on devrait légitement
demander aux auteurs du dit compilateur de s'occuper de la performance
du compilateur -- car cela m'étonnerait que le goulot d'étranglement
soit pour<stdio.h> et nettement moins pour d'autres combinaisons
d'entêtes, et ceci de manière déterminante pour le projet.



<stdio.h> ici n'est qu'un exemple, et sans doute pas le meilleur. Bien
sûr les compilateurs ont leur part de responsabilité dans le temps de
compilation, et il existe des techniques bien connues (en-têtes
précompilés par exemple) pour accélérer leur performance. Néanmoins je
pense que les programmeurs ont aussi leur part de responsabilité et il
est souvent possible de fournir, à fonctionnalité équivalente, un code
plus rapide à compiler.

--
Richard
Avatar
bpascal123
On 14 sep, 13:31, Gabriel Dos Reis wrote:
(Marc Espie) writes:

[...]

| Non, par contre, comprendre ce qu'on peut faire avec, pourquoi c'est
| indispensable, montrer les idiomes vitaux aux etudiants, ca c'est
| complique.




Bonjour,

Je me considère comme autodidacte en effet j'ai reçu une formation en
comptabilité à distance et de fait, je pense être devenu autodidacte
pour apprendre en programmer en C. Je voudrais comprendre ce langage
pour passer à d'autres langages. Je crois comprendre que python, c++,
java...sont écrit en C, alors comprendre le C même si ça demande
beaucoup de temps doit en valoir la peine...

Apprendre à programmer en C ne m'a pas demandé plus de motivation
qu'apprendre le droit fiscal ou la gestion financière. Actuellement,
j'avais beaucoup de mal avec les pointeurs et il semble que je ne sois
pas le seul.

Mais en fait, j'ai commencé un chapitre de la manière classique (cours
et exercices), jusque-là j'apprends certains codes que je trouve
intéressants par coeur...) et par la manière classique, j'ai pu
commencer à apercevoir la "puissance" des pointeurs. Ce qui fait que
maintenant, je suis un peu moins réluctant avec du code qui contient
des pointeurs quand je connais leur utilité et que je commence à
comprendre leur fonctionnement. De fait, je ne sais pas si apprendre
par coeur est un avantage.

En fait, dans le langage C, aujourd'hui ce qui me pose le plus de
difficulté, c'est la portabilité entre Windows et Linux et les modes
de saisie utilisateur ou autre avec scanf, frets, getchar...et les
caractères de 'n' et autres. C'est vrai que je n'ai pas encore mis
complètement un pied dans les pointeurs ni une grande maîtrise des
fonctions.
Mais comment se fait-il qu'une simple saisie sur un clavier puisse
fonctionner sous Windows et donner une boucle d'erreurs sans fin sous
Linux ou inversement?

J'ai 2 idées sur la question :

1° le passage d'une norme à une autre ne rend pas les choses faciles
entre les systèmes qui évoluent, mais pas au même moment que les
organismes de normalisation, d'où des décalages de comportements entre
les OS ....

2° n'ayant pas suivie de formation en informatique, j'ai des lacunes
assez importantes pour comprendre certains concepts comme le lien
entre un périphérique clavier et la mémoire "buffer" qui je crois se
trouve dans la partie haute de la ram. Je suppose qu'il doit aussi y
avoir un lien avec heap, stack et autre...

En C, les fonctions de saisie clavier avec lesquelles je considère
travailler sont scanf pour les entiers seulement, fgets (...stdin)
pour les caractères et getchar() soit pour saisir un caractère isolé
ou pour "nettoyer" le buffer. Seulement, je n'arrive pas à comprendre
l'action de getchar sur le buffer.

Je comprends seulement que scanf et frets stockent tout ce qui rentre
par le clavier et également le "return carriage" : 'n' et autres EOF
ou -1 ... et getchar() "attrape" ce 'n' ou -1 quand il est présent.
- - -Mais le 'n' ne me semble pas présent au même moment dans la
même partie du code dans Windows et Linux...

Je ne suis pas sûr de mon - - -, car je n'ai qu'un ordinateur et je ne
peux pas tester simultanément. Peut-être je dois penser à la
virtualisation. Ma préférence irait pour virtualiser xp sous Linux
avec virtualbox. Je pourrais compiler comme si j'étais sous xp depuis
le démarrage?

Bref pour le 2e point, je suis un peu dans l'obscurité. J'ai vu un
livre dans une librairie pas loin de chez moi (au moins 500pages) sur
l'architecture des systèmes d'exploitation(je ne sais plus le titre,
je peux le savoir...).

Le prix n'est pas égal au nombre de pages, mais me fait quand même
réfléchir. Usenet offre beaucoup de réponses à ce sujet. J'ai
également pu tester un code sur le site du zéro qui fait appel à
getchar dans une fonction distincte, mais tout ça ne me fait pas
comprendre ce qui se cache derrière cette implémentation en langage
C.
Alors je dois encore me trouver un livre dans ce domaine?

Pascal
Avatar
Marc Boyer
Le 14-09-2009, Stephane Legras-Decussy a écrit :

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



Ben non.

D'une part, il y a déjà tous les typedef de portabilité.

Et puis, le "typedef", ça sert aussi à dire "ceci est un type métier,
et allez pas regarder comment c'est implanté, c'est pas vos oignons
et ça pourrait changer".
Ceci dit, j'ai tendance à l'encapsuler dans un struct même s'il
y a qu'un entier dedans.

Après, vu les règles de conversions implicites, faire une typedef
sur un type entier sans dire dans quelle famille il est, c'est
un peu vicieux.

Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?article1&id_mot0
Avatar
Marc Boyer
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 ?

En plus, dans ton exemple, on retourne un tableau, il
me semble, et c'est pas trop permis en C il me semble.

Mais bon, ça permet de retrouver Java: à part int,
float, bool et leurs copains, tout est référence...

Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?article1&id_mot0
Avatar
Marc Boyer
Le 14-09-2009, Gabriel Dos Reis a écrit :
Marc Boyer writes:

[...]

| >| > Les étudiants ont lab work 2 fois 50 min par semaine (j'ai un chargé de
| >| > TD, mais j'insiste à assister à chaque fois que je peux.)
| >|
| >| Mais tu dis demander 10h de travail perso hebdomadaire, non ?
| >
| > Au minimum.
|
| Ce ne sont pas les mêmes conditions. J'avais juste à la
| fin, sur un mois environ, 30h de projet à l'emplois du temps,
| et les étudiants en passaient entre 40h (les bons) et 150h
| (les mauvais) en dehors des heures de cours.

Si tu n'as pas assez d'heures de cours, tu les prends là où ça se
trouve : les étudiants ont en général beaucoup de temps libre.



Oui, encoe que, on les charge un peu d'où je viens.

Tu leurs
donnes des projets à faire ; ce sont des exos, cela fait partie de la
note finale.



Et ben non... Le "je-sais-plus-quoi" voté en début d'année détaille les
modalités d'évaluation, et on ne peut rien ajouter ou enlever. Et si
on met trop de chose à faire en dehors des heures, on se fait taper
sur les doigts.

Il est presque illusoire de prétendre former quelqu'un à la
programmation si cette personne ne consent passer qu'au plus 30h.



En fait, le programme de prog complet s'était:
Algo/Pascal : 17h cours + 17h TD + 17h TP + 17h Projet
C : 9h cours + 17h TD + 20h TP + 30h Projet
Java/POO : 17h cours + 14h TD + 14h TP + 20h Projet

Avec un cours par semestre en gros.

On est à bien plus de 30h. Ca fait 200h à l'emplois du temps.
Il y a une centaine d'heure réparties sur les 3 projets que
les étudiants font en plus des heures à l'emplois du temps.

La première chose que je fais le au premier cours est de présenter le
« syllabus »

http://courses.cs.tamu.edu/gdr/2009.fall-315/syllabus.pdf



J'ai lu ça, t'a donné la ref dans un autre post.
Je viens de lire aussi "programming in an undergraduate CS curriculum"
de BS que tu avais mentionné.
J'ai du mal à comparer, car il parle en semaines, mais en gros, il
a 12 semaines et une vingtaine de "lectures" pour faire ce que nous
faisions en Algo/Pascal. Et il reconnait "this material is very extensive
for a first course".

Après, ton cours de C, tu as une vingtaine de "lecture", autant
de TD (j'ai oublié le terme exact) et plus de 10h de travail perso
par semaine, pendant combien de semaines ?

C'est une sorte de contrat : en fait, ce semestre-ci, le premier cours
n'était que ça. Ils savent ce que j'attends d'eux et ils savent quoi
attendre de moi. S'ils ne sont pas d'accord, ils ne reviennent pas
(ils ont en général quelques jours < 5 pour se désinscrire).
Si je les vois la semaine d'après, c'est qu'ils ont accepté le contrat.



De loin, ça a l'air bien.
Tu cherches un chargé de TD ? ;-)

Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?article1&id_mot0