é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,
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
Gabriel Dos Reis, le 14/09/2009 a écrit :
Richard Delorme <abulmo@nospam.fr> 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.
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
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 ?
Pierre Maurette a écrit :
int* p = NULL;
/* du code */
p = &a;
Je n'ai pas affecté de valeur à a avant de l'utiliser.
Je n'ai pas affecté de valeur à a avant de l'utiliser.
Et justement, c'est pas interdit ça ?
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/
Gabriel Dos Reis scripsit:
Manuel Pégourié-Gonnard <mpg+news@elzevir.fr> 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/
| 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/
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...
In article <87zl8xisj1.fsf@gauss.cs.tamu.edu>,
Gabriel Dos Reis <gdr@cs.tamu.edu> 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...
| - 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...
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)
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.
(c'est exactement la raison qui fait que C++ a un iosfwd)
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)
Oui, mais toi tu fais du C++. Tu sais aussi bien que moi que les usages sont differents. ;-)
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...
In article <20090914175932.16931.37406.XPN@roth.elzevir.fr>,
Manuel Pégourié-Gonnard <mpg+news@elzevir.fr> 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...
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...
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++....
In article <mn.73da7d994f4c3f2b.79899@wanadoo.fr>,
Pierre Maurette <maurettepierre@wanadoo.fr> 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++....
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++....
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
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.
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
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
Gabriel Dos Reis, le 14/09/2009 a écrit :
Pierre Maurette <maurettepierre@wanadoo.fr> 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.
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.