Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Question entretien C++ - doutes.

95 réponses
Avatar
David Fleury
Bonjour,

voici une des questions que je pose pour lors de mes entretiens pour des
développeurs avec expérience orienté C++

"Ecrire une fonction qui renverse une chaine (ex: ABC -> CBA, AE -> EA, ...)

Après avoir posé la question deux ou trois fois déjà, je suis surpris
des réponses (souvent fausses). Je laisse volontairement le choix au
candidat d'utiliser (char* ou std::string) et/ou une fonction modifiant
la chaine entrée ou retournant une nouvelle chaine, et l'utilisation de
la STL est autorisé.

A votre avis, est-ce que la question n'est pas trop mauvaise ?

David.

PS : Dans le même genre, il y a la fonction EstPalindrome qui semble
bloquer.

5 réponses

6 7 8 9 10
Avatar
James Kanze
On Nov 4, 10:40 am, Wykaaa wrote:
James Kanze a écrit :> On Nov 3, 1:45 pm, Wykaaa wrot e:
>> Jean-Marc Bourguet a écrit :
>>> Wykaaa writes:

>>>> Jean-Marc Bourguet a écrit :
>>>>> Wykaaa writes:

>>>>>> Jean-Marc Bourguet a écrit :
>>>>>>> Wykaaa writes:
>>>>>>> Les tableaux C sont déjà une source de confusion assez grand e comme
>>>>>>> cela; faire croire que le nom d'un tableau a un type pointeur ne fait
>>>>>>> qu'augmenter la confusion -- en particulier en C++.
>>>>>> Désolé, mais "un type pointeur", ça ne veut rien dire
>>>>>> puisque les pointeurs sont... typés.
>>>>> Bizarre, l'expression se trouve dans les normes C90,
>>>>> C++98, C99 et le dernier brouillon disponible de C++0X
>>>>> avec le sens que je lui donne ici.
>>>> La norme ne devrait pas dire "type pointeur", elle devrait
>>>> dire "de nature pointeur".



>>> Le mot est en italique dans la partie que j'ai regardé: la
>>> norme donne une définition du terme. Au même endroit
>>> qu'elle défini les autres types dérivés.



>> J'ai cherché... et je n'ai pas trouvé d'endroit où "pointer
>> type" était en italique dns la référence que tu m'as fournie
>> plus loin.



> C'est vrai que dans la définition (§3.9.2), elle parle de
> « pointers », et non « pointer types », mais vu le nom de la
> section (« Composite types »), je crois que c'est clair que ce
> dont elle parle ici, ce sont des types pointeur (et non des
> variables pointeurs, etc.).



Il faut vraiment lire entre les lignes !
Décidément, je n'aime pas du tout le terme "pointer type" qui
sème la confusion.



Je ne sais pas pourquoi. Il me semble que « pointer type » est
tout à fait clair. Quand on utilise le mot « pointer », sans
autre qualification, on ne sait pas d'office si 1) c'est le
type, 2) c'est un résultat d'une expression ou 3) c'est un
objet. L'expression « pointer type » clarifie qu'il s'agit du
premier.

[...]
>> Pffft : 1350 pages, je n'ai pas le courage...
>> Il n'y a pas de vrai glossaire C++ dans la norme. C'est très
>> regrettable. Quantité de termes apparemment techniques qui
>> figurent dans le texte ne sont définis nulle part.



> En tant qu'annex, je suis bien d'accord. Tu te portes volentaire
> pour le réaliser ?



Je sais, c'est facile de critiquer mais je n'ai pas de temps pour ça,
hélas...



Je comprends bien:-). C'était juste une façon un peu ironique
d'expliquer pourquoi il n'y est pas.

> [...]
>>>>>> S'il n'y avait pas cette "équivalence"
>>>>>> pointeur/tableau, il n'y aurait pas besoin des [] pour
>>>>>> indiquer à delete que le pointeur pointe sur un tableau
>>>>>> alloué dynamiquement afin d'appeler les destructeurs
>>>>>> pour chaque instance.
>>>>> J'ai du mal à comprendre ce que tu veux dire. Dans



>>>>> int* t = new int[10];
>>>>> delete[] t;



>>>>> la conversion implicite d'un tableau en un pointeur
>>>>> n'intervient pas.
>>>> Certes mais il faut mettre les crochets car C, donc C++,
>>>> n'est pas capable de distinguer, de lui-même, entre un
>>>> pointeur sur variable scalaire et un pointeur sur tableau.



> C'est parce qu'ici, il n'y a pas de pointeur sur tableau.



>>> Ne referais-tu pas la même erreur de nomenclature que
>>> celle qui a lancé cette discussion?



>>> int* x;



>>> int (*x)[10];



>> int* i = new int;
>> int* p = new int[10];
>> delete i;
>> delete [] p;
>> Pourquoi les [] seraient-ils nécessaires?
>> C'est cela que je voulais dire.



> Parce que la norme l'exige. Il n'y a pas d'autre raison. La
> norme distingue deux types d'opérateur new qui renvoient un
> T*, selon le type alloué. Et donc, deux types d'opérateur
> delete.



Ce que je ne comprends pas c'est pourquoi la norme l'exige.
Quelle est la raison à l'origine de cette décision ?



Comme dans tellement d'autres cas : pour des raisons
historiques. Au départ, il fallait non seulement le [], mais
aussi que tu y mets le nombre d'éléments. Ensuite... Ne jamais
l'exiger imposerait un petit coût supplémentaire aux allocations
et aux libérations des scalaires. Or, la règle, c'est ne jamais
avoir à payer pour quelque chose dont tu ne te sers pas. Et vue
que des programmes qui utilise un new[] sont en fait rarissime,
certains se sont opposés à ce qu'il ajoute le moindre coût aux
programmes qui ne l'utilisent pas.

> C'est bête, mais dans la pratique, je ne me suis jamais
> servi d'un new [] ni d'un delete []. Qu'un débuttant ne
> sache même pas qu'ils existent ne me gènerait pas
> outremesure.



C'est bête car je préconise que tout delete soit accompagné
des crochets pour faciliter la maintenance.
En effet :
classe Client {...};
Client* cl = new Client;
plus loin : delete cl;
Un jour on change la déclaration de cl : Client* cl = new Client [10] ;
delete cl ne détruit pas les instances de Client créées dans le tab leau
alloué dynamiquement.



Ce jour-là, je ne m'attendrais pas à le voit dans ma vie. Et le
jour où ça arrive, j'aurais bien à modifier pas mal d'autres
choses aussi.

Normalement, delete [] xxx est accepté, même si xxx ne pointe
pas sur un tableau.



Pas du tout. delete[] quand tu as fait un new sans les [], c'est
aussi comportement indéfini. Et dans la pratique, je ne connais
pas de compilateur où il marche.

[...]
>> Je relève quand même dans la norme que :
>> 4.2 Array-to-pointer conversion [conv.array]
>> 1 An lvalue or rvalue of type ?array of N T? or ?array of
>> unknown bound of T? can be converted to an rvalue of type
>> ?pointer to T?. The result is a pointer to the first element
>> of the array. Le chapitre 4 traite des conversions standards
>> et commence par "Standard conversions are implicit conversions
>> defined for built-in types". Qu'on le veuille ou non, la
>> conversion d'un nom de tableau en pointeur sur son premier
>> élément est bien im-pli-cite et, donc, standard.



> Certes. Qui a dit le contraire ?



La formulation de Jean-Marc Bourguet peut le laisser croire,
quelque part, dans ce fil, je cite : "faire croire que le nom
d'un tableau a un type pointeur ne fait qu'augmenter la
confusion -- en particulier en C++."



Aucun rapport. Un int se laisse implicitement convertir en
double aussi. Ce n'est pas pour autant qu'on doit faire croire
que le nom d'un int, c'est en fait un double. Au contraire ; on
insiste sur le fait qu'il y a une conversion implicite entre
deux types différents.

[...]
>> En C, lors de la normalisation, on s'est bien débarrassé du
>> trait de langage très ennuyeux qui consistait à pouvoir faire
>> un branchement au milieu d'un bloc d'instruction. En effet,
>> dans ce cas, le C dit de K&R, avait la sémantique curieuse
>> qu'il fallait allouer les variables locales déclarées
>> éventuellement dans le bloc mais s'il y avait des
>> initialisations, le compilateur n'était pas obligé de les
>> faire lors du branchement...



> J'ai dû mal comprendre. J'ai l'impression que tu dis qu'on s'est
> débarrassé de quelque chose comme :



> void
> f()
> {
> goto toto ;
> {
> int i ;
> toto:
> i = 43 ;
> }
> }



> Or, c'est un programme on ne peut plus légal. (Pas beau du
> tout, mais légal, quand même.)



Non, j'ai parlé d'initialisation et non d'affectation. Le cas
que je décrivais est :



void
> f()
> {
> goto toto ;
> {
> int i = 43 ;
> toto:
> ...
une utilisation de i
...
> }
> }



L'ancien C disait que, dans ce cas,quand on fait le
branchement à toto, i doit avoir été alloué dans le bloc mais
l'initialisation n'est pas forcément effectuée...



C'est parce que l'ancien C n'a pas la même définition
d'initialisation que le C++. C'est effectivement une
incompatibilité, mais dans la pratique, elle ne doit toucher
pratiquement aucun programme. Tandis qu'ôter la conversion de
tableau en pointeur et définir [] comme opérateur sur des
tableaux irait loin, très loin. Les consequences ne sont pas les
mêmes.

>> Il y a des décisions apparemment anodines qui coûtent très
>> cher par la suite quand on normalise. Les choix de
>> priorités des opérateurs (en particulier les opérateurs bit
>> à bit) en est un.



> Je suis bien d'accord avec toi, mais ça date. (Voir
>http://www.quut.com/c/dmr-on-or.html#mainpour la question des
>priorités, par exemple.) La compatibilité avec C, c'est
>probablement la raison principale pour la réussite de C++.
>C'est aussi, malheureusement, la source de pas mal de
>problèmes et d'ambiguïtés ; je crois qu'on peut dire que le C
>n'a pas vraiment été conçu de façon à servir de base de tant
>de languages.



C était à l'origine une "commodité" pour éviter que K&R code
Unix en assembleur.



Les premiers Unix était en assembleur. Et le C a été conçu pour
plus que ça, dès le début. Seulement, il a été conçu dans un
contexte historique particulier, dont il faut tenir compte pour
le comprendre.

Le langage C n'était pas du tout destiné au public (et ça se
voit !). Il aurait dû resté interne aux Bell Labs...



Tout à fait d'accord. C'est une base vraiment désastreuse pour
des langages qui ont suivis.

>> J'ai eu l'occasion d'auditer de très nombreux programmes
>> C++. C'est une des erreurs les plus fréquentes que j'ai
>> rencontrée.



> Qu'est-ce qui est l'une des erreurs les plus fréquentes ?
> D'utiliser les tableaux de type C quand il existe de
> meilleurs alternatifs ?



Non la confusion sur la priorités des opérateurs, dans des
expressions comme :
x & ox00FF + 5 où l'intention du programmeur était de faire
(x & ox00FF) + 5 mais ceci est interprété comme : x & (ox00FF + 5) ca r +
est plus prioritaire que &, ce qui est une grosse erreur de conception
du langage.



Là aussi, je ne l'ai pas vu souvent. Peut-être parce que
l'utilisation de & et de | est déjà assez rare.

De toute façon, K&R étaient très bons en système mais assez
nuls en langage (comme souvent chez les "hommes système").



Je n'ai pas vu où ils étaient mieux en système. Ce que je vois,
en revanche, ce n'est pas ce qu'ils soient nuls en quoique ce
soit ; c'est qu'ils s'adressaient toujours aux problèmes
immédiats, sans se soucier de la pûreté ou de la propreté
conceptuelle. Ce qui a sa place, mais ce qui ne donne pas
souvent des bonnes bases pour des choses plus élaborées.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
Jean-Marc Bourguet
Wykaaa writes:

Le langage C ne doit sa popularité qu'au succès d'Unix car le couple C-Unix
est l'équivalent (du moins dans le monde système) de l'ancien couple
PL/1-Multics.



Il me semblait que le C s'est echappe du monde Unix vers la fin des annees
70 et a eu un succes plus large -- c'est d'ailleurs ce qui a justifie sa
normalisation et une partie des comportements indefinis sont la pour tenir
compte de ca.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Wykaaa
Jean-Marc Bourguet a écrit :
Wykaaa writes:

Décidément, je n'aime pas du tout le terme "pointer type" qui sème la
confusion.



Je ne vois rien qui cause de la confusion. Les pointeurs sont une famille
de types -- on pourrait facilement imaginer un langage qui utilise la meme
syntaxe pour construire les types pointeurs que pour instancier des types
templates -- un type pointeur est un de ces types. Tout comme on a des
types entiers (int, long), des types tableaux, des types classes etc...



Ok. C'est une façon de voir.

Ce que je ne comprends pas c'est pourquoi la norme l'exige. Quelle est la
raison à l'origine de cette décision ?



La non difference entre un pointeur vers un objet isole et un pointeur vers
un objet d'un tableau (ou meme le premier objet d'un tableau).



Cette non distinction dans le langage, c'est bien ce que je lui reproche.

C'est bête, mais dans la pratique, je ne me suis jamais servi
d'un new [] ni d'un delete []. Qu'un débuttant ne sache même pas
qu'ils existent ne me gènerait pas outremesure.


C'est bête car je préconise que tout delete soit accompagné des crochets
pour faciliter la maintenance.



Pour facilite la maintenance d'un cas extremement rare, tu compliques le
cas usuel? Les cas ou j'ai du faire cette transformation sont rarissimes,
s'ils existent. Ma premiere reaction c'etait que j'utiliserais un
std::vector<>, mais ma deuxieme est "pourquoi alors est-ce que cl est un
pointeur?".



Je suis d'accord qu'en C++, on va utiliser std::vector<>, mais la
discussion n'était pas là.

En effet :
classe Client {...};
Client* cl = new Client;
plus loin : delete cl;
Un jour on change la déclaration de cl : Client* cl = new Client [10];
delete cl ne détruit pas les instances de Client créées dans le tableau
alloué dynamiquement.
Normalement, delete [] xxx est accepté, même si xxx ne pointe pas sur un
tableau.



delete[] n'est accepte que si il y a eu un new[].



Dans les années 90, ce n'était pas le cas. J'avais fait le test sur
plusieurs compilateurs qui ne disaient rien et qui faisaient le travail
sans problème, mais je ne me rappelle plus lesquels (probablement celui
de HP en tout cas, à l'époque).

Donc

Client* cl = new Client[1];

delete[] cl;

ou

Client* cl = new Client;

delete cl;

Mais pas

Client* cl = new Client;

delete[] cl;

Sauf qu'au départ, il y avait le C. Qui lui évolue de B.


Pour moi, ce n'était pas une raison suffisante. Le processus de
normalisation n'est souvent qu'une série de compromis entre "marchands de
tapis".



Comme tout ce qui cherche une evolution plutot qu'une revolution. Et
l'experience montre qu'on survit plus longtemps avec une evolution
imparfaite qu'une revolution qui detruit tout l'existant.



1789 ;-) ?


Seulement, comment l'améliorer sans briser la comptabilité C. À
la fin, la décision était de les laisser tels quels, en
fournissant des altérnatifs nouveaux supérieur (genre
std::vector).


D'accord, cette décision n'a pas brisé la compatibilité, mais pour être
"propre", il faudrait donc transformer toutes les utilisations des tableaux
C en vector lors du passage de C à C++ ou ne jamais utiliser les tableaux C
en C++. Dans ce cas, ça ne servait à rien de conserver la compatibilité...



Le C++ est comme le C, un langage qui a evolue sur une periode *longue*. A
chaque fois au moment de la normalisation c'etait un langage d'une
quinzaine d'annees deja utilise pour des choses non triviales.



Certes. La tâche de normalisation d'un langage n'est jamais facile pour
des langages qui ont déjà un long historique, ce qui était le cas de C
et de C++.

Je relève quand même dans la norme que :
4.2 Array-to-pointer conversion [conv.array]
1 An lvalue or rvalue of type “array of N T” or “array of
unknown bound of T” can be converted to an rvalue of type
“pointer to T”. The result is a pointer to the first element
of the array. Le chapitre 4 traite des conversions standards
et commence par "Standard conversions are implicit conversions
defined for built-in types". Qu'on le veuille ou non, la
conversion d'un nom de tableau en pointeur sur son premier
élément est bien im-pli-cite et, donc, standard.


Certes. Qui a dit le contraire ?


La formulation de Jean-Marc Bourguet peut le laisser croire, quelque part,
dans ce fil, je cite : "faire croire que le nom d'un
tableau a un type pointeur ne fait qu'augmenter la confusion -- en
particulier en C++."



J'ai dit et repete, "le nom d'un tableau designe un objet de type tableau.
Tous les objets de types tableau (qu'il soit nomme ou pas) sont convertis
implicitement dans la plupart des contextes en un pointeur vers leur
premier element".



On est donc d'accord.

Sans rancune.
On peut clore cette discussion.
Avatar
Wykaaa
James Kanze a écrit :
On Nov 4, 10:40 am, Wykaaa wrote:
James Kanze a écrit :> On Nov 3, 1:45 pm, Wykaaa wrote:
Jean-Marc Bourguet a écrit :
Wykaaa writes:
Jean-Marc Bourguet a écrit :
Wykaaa writes:
Jean-Marc Bourguet a écrit :
Wykaaa writes:
Les tableaux C sont déjà une source de confusion assez grande comme
cela; faire croire que le nom d'un tableau a un type pointeur ne fait
qu'augmenter la confusion -- en particulier en C++.


Désolé, mais "un type pointeur", ça ne veut rien dire
puisque les pointeurs sont... typés.


Bizarre, l'expression se trouve dans les normes C90,
C++98, C99 et le dernier brouillon disponible de C++0X
avec le sens que je lui donne ici.


La norme ne devrait pas dire "type pointeur", elle devrait
dire "de nature pointeur".











Le mot est en italique dans la partie que j'ai regardé: la
norme donne une définition du terme. Au même endroit
qu'elle défini les autres types dérivés.









J'ai cherché... et je n'ai pas trouvé d'endroit où "pointer
type" était en italique dns la référence que tu m'as fournie
plus loin.







C'est vrai que dans la définition (§3.9.2), elle parle de
« pointers », et non « pointer types », mais vu le nom de la
section (« Composite types »), je crois que c'est clair que ce
dont elle parle ici, ce sont des types pointeur (et non des
variables pointeurs, etc.).





Il faut vraiment lire entre les lignes !
Décidément, je n'aime pas du tout le terme "pointer type" qui
sème la confusion.



Je ne sais pas pourquoi. Il me semble que « pointer type » est
tout à fait clair. Quand on utilise le mot « pointer », sans
autre qualification, on ne sait pas d'office si 1) c'est le
type, 2) c'est un résultat d'une expression ou 3) c'est un
objet. L'expression « pointer type » clarifie qu'il s'agit du
premier.

[...]
Pffft : 1350 pages, je n'ai pas le courage...
Il n'y a pas de vrai glossaire C++ dans la norme. C'est très
regrettable. Quantité de termes apparemment techniques qui
figurent dans le texte ne sont définis nulle part.







En tant qu'annex, je suis bien d'accord. Tu te portes volentaire
pour le réaliser ?





Je sais, c'est facile de critiquer mais je n'ai pas de temps pour ça,
hélas...



Je comprends bien:-). C'était juste une façon un peu ironique
d'expliquer pourquoi il n'y est pas.



Mais si j'avais le temps, je pense que je l'aurais vraiment fait !

[...]
S'il n'y avait pas cette "équivalence"
pointeur/tableau, il n'y aurait pas besoin des [] pour
indiquer à delete que le pointeur pointe sur un tableau
alloué dynamiquement afin d'appeler les destructeurs
pour chaque instance.


J'ai du mal à comprendre ce que tu veux dire. Dans













int* t = new int[10];
delete[] t;













la conversion implicite d'un tableau en un pointeur
n'intervient pas.


Certes mais il faut mettre les crochets car C, donc C++,
n'est pas capable de distinguer, de lui-même, entre un
pointeur sur variable scalaire et un pointeur sur tableau.











C'est parce qu'ici, il n'y a pas de pointeur sur tableau.





Ne referais-tu pas la même erreur de nomenclature que
celle qui a lancé cette discussion?









int* x;









int (*x)[10];









int* i = new int;
int* p = new int[10];
delete i;
delete [] p;
Pourquoi les [] seraient-ils nécessaires?
C'est cela que je voulais dire.







Parce que la norme l'exige. Il n'y a pas d'autre raison. La
norme distingue deux types d'opérateur new qui renvoient un
T*, selon le type alloué. Et donc, deux types d'opérateur
delete.





Ce que je ne comprends pas c'est pourquoi la norme l'exige.
Quelle est la raison à l'origine de cette décision ?



Comme dans tellement d'autres cas : pour des raisons
historiques. Au départ, il fallait non seulement le [], mais
aussi que tu y mets le nombre d'éléments.



Oui je m'en souviens.

Ensuite... Ne jamais
l'exiger imposerait un petit coût supplémentaire aux allocations
et aux libérations des scalaires. Or, la règle, c'est ne jamais
avoir à payer pour quelque chose dont tu ne te sers pas. Et vue
que des programmes qui utilise un new[] sont en fait rarissime,
certains se sont opposés à ce qu'il ajoute le moindre coût aux
programmes qui ne l'utilisent pas.



J'ai toujours utilisé abondamment des new[].

C'est bête, mais dans la pratique, je ne me suis jamais
servi d'un new [] ni d'un delete []. Qu'un débuttant ne
sache même pas qu'ils existent ne me gènerait pas
outremesure.





C'est bête car je préconise que tout delete soit accompagné
des crochets pour faciliter la maintenance.
En effet :
classe Client {...};
Client* cl = new Client;
plus loin : delete cl;
Un jour on change la déclaration de cl : Client* cl = new Client [10];
delete cl ne détruit pas les instances de Client créées dans le tableau
alloué dynamiquement.



Ce jour-là, je ne m'attendrais pas à le voit dans ma vie. Et le
jour où ça arrive, j'aurais bien à modifier pas mal d'autres
choses aussi.



Mais moi, je l'ai vu sur plusieurs projets !!

Normalement, delete [] xxx est accepté, même si xxx ne pointe
pas sur un tableau.



Pas du tout. delete[] quand tu as fait un new sans les [], c'est
aussi comportement indéfini. Et dans la pratique, je ne connais
pas de compilateur où il marche.



Depuis quand ?
Dans les années 90 beaucoup de compilateurs acceptaient ceci et
faisaient le travail. J'avais fait des tests sur de nombreux
compilateurs à l'époque. Au moins Sun, HP et IBM

[...]
Je relève quand même dans la norme que :
4.2 Array-to-pointer conversion [conv.array]
1 An lvalue or rvalue of type ?array of N T? or ?array of
unknown bound of T? can be converted to an rvalue of type
?pointer to T?. The result is a pointer to the first element
of the array. Le chapitre 4 traite des conversions standards
et commence par "Standard conversions are implicit conversions
defined for built-in types". Qu'on le veuille ou non, la
conversion d'un nom de tableau en pointeur sur son premier
élément est bien im-pli-cite et, donc, standard.







Certes. Qui a dit le contraire ?





La formulation de Jean-Marc Bourguet peut le laisser croire,
quelque part, dans ce fil, je cite : "faire croire que le nom
d'un tableau a un type pointeur ne fait qu'augmenter la
confusion -- en particulier en C++."



Aucun rapport. Un int se laisse implicitement convertir en
double aussi. Ce n'est pas pour autant qu'on doit faire croire
que le nom d'un int, c'est en fait un double. Au contraire ; on
insiste sur le fait qu'il y a une conversion implicite entre
deux types différents.



On parle d'équivalence tableau/pointeur, pas d'identité de type.

[...]
En C, lors de la normalisation, on s'est bien débarrassé du
trait de langage très ennuyeux qui consistait à pouvoir faire
un branchement au milieu d'un bloc d'instruction. En effet,
dans ce cas, le C dit de K&R, avait la sémantique curieuse
qu'il fallait allouer les variables locales déclarées
éventuellement dans le bloc mais s'il y avait des
initialisations, le compilateur n'était pas obligé de les
faire lors du branchement...







J'ai dû mal comprendre. J'ai l'impression que tu dis qu'on s'est
débarrassé de quelque chose comme :





void
f()
{
goto toto ;
{
int i ;
toto:
i = 43 ;
}
}





Or, c'est un programme on ne peut plus légal. (Pas beau du
tout, mais légal, quand même.)





Non, j'ai parlé d'initialisation et non d'affectation. Le cas
que je décrivais est :



void
> f()
> {
> goto toto ;
> {
> int i = 43 ;
> toto:
> ...
une utilisation de i
...
> }
> }



L'ancien C disait que, dans ce cas,quand on fait le
branchement à toto, i doit avoir été alloué dans le bloc mais
l'initialisation n'est pas forcément effectuée...



C'est parce que l'ancien C n'a pas la même définition
d'initialisation que le C++. C'est effectivement une
incompatibilité, mais dans la pratique, elle ne doit toucher
pratiquement aucun programme.


Lors de la première normalisation du C, certains voulaient conserver ce
trait de langage. Si mes souvenirs sont exacts, il me semble que NEC
utilisait ce trait de langage à plusieurs endroits dans ses systèmes...

Tandis qu'ôter la conversion de
tableau en pointeur et définir [] comme opérateur sur des
tableaux irait loin, très loin. Les consequences ne sont pas les
mêmes.



C'est pourtant ce qu'il aurait fallu faire AMHA.

Il y a des décisions apparemment anodines qui coûtent très
cher par la suite quand on normalise. Les choix de
priorités des opérateurs (en particulier les opérateurs bit
à bit) en est un.







Je suis bien d'accord avec toi, mais ça date. (Voir
http://www.quut.com/c/dmr-on-or.html#mainpour la question des
priorités, par exemple.) La compatibilité avec C, c'est
probablement la raison principale pour la réussite de C++.
C'est aussi, malheureusement, la source de pas mal de
problèmes et d'ambiguïtés ; je crois qu'on peut dire que le C
n'a pas vraiment été conçu de façon à servir de base de tant
de languages.





C était à l'origine une "commodité" pour éviter que K&R code
Unix en assembleur.



Les premiers Unix était en assembleur.



du PDP 8, il me semble.

Et le C a été conçu pour
plus que ça, dès le début.




Je n'en suis pas certain.

Seulement, il a été conçu dans un
contexte historique particulier, dont il faut tenir compte pour
le comprendre.



Pas de problème, je connais le contexte et j'ai fait un compilateur C.

Le langage C n'était pas du tout destiné au public (et ça se
voit !). Il aurait dû resté interne aux Bell Labs...



Tout à fait d'accord. C'est une base vraiment désastreuse pour
des langages qui ont suivis.



Et bien voilà. Tu as tout dit ;-)

J'ai eu l'occasion d'auditer de très nombreux programmes
C++. C'est une des erreurs les plus fréquentes que j'ai
rencontrée.







Qu'est-ce qui est l'une des erreurs les plus fréquentes ?
D'utiliser les tableaux de type C quand il existe de
meilleurs alternatifs ?





Non la confusion sur la priorités des opérateurs, dans des
expressions comme :
x & ox00FF + 5 où l'intention du programmeur était de faire
(x & ox00FF) + 5 mais ceci est interprété comme : x & (ox00FF + 5) car +
est plus prioritaire que &, ce qui est une grosse erreur de conception
du langage.



Là aussi, je ne l'ai pas vu souvent. Peut-être parce que
l'utilisation de & et de | est déjà assez rare.



Ca dépend du type d'application. Moi je l'ai vu très souvent dans des
applications temps réel (militaire, musicales en particulier).
Dans l'exploitation du protocole MIDI, on utilise beaucoup ces
opérateurs et, en général, dans tout ce qui est interprétation de
protocole.

De toute façon, K&R étaient très bons en système mais assez
nuls en langage (comme souvent chez les "hommes système").



Je n'ai pas vu où ils étaient mieux en système.



Tu m'intéresses, car je leur faisais au moins crédit pour leurs
compétences système...

Ce que je vois,
en revanche, ce n'est pas ce qu'ils soient nuls en quoique ce
soit ; c'est qu'ils s'adressaient toujours aux problèmes
immédiats, sans se soucier de la pûreté ou de la propreté
conceptuelle. Ce qui a sa place, mais ce qui ne donne pas
souvent des bonnes bases pour des choses plus élaborées.



On peut clore cette discussion fort intéressante si tu n'y vois pas
d'inconvénient mais elle montre que l'élaboration d'un langage de
programmation est quelque chose de très délicat qui ne peut être faite à
la légère.
Avatar
Michael DOUBEZ
Jean-Marc Bourguet a écrit :
Michael DOUBEZ writes:

Ce qui pose la question des VLAs pour C++0x. Je comprends que ça puisse
rendre la vie de compilateurs plus difficile mais c'est AMA là où il y a le
plus de travail quand on porte du code C99 vers C++ (ou quand le code à été
écrit sur un compilateur souple).



Je ne crois pas que ce soit un probleme de travail pour les compilateurs --
a priori un ordre de grandeur ou deux en moins que pour les concepts --
mais c'est surtout un probleme de difficulte de definition par rapport aux
benefices attendus et donc de l'absence de quelqu'un pour prendre la peine
d'examiner les consequences et de faire une proposition.



Zut, je savais que j'avais oublié quelque chose; tant pis pour C++0x. Il
reste toujours TR3 ;).

Enfin, je n'y avais pas réfléchit mais j'imagine qu'un type paramétrique
au runtime aurait effectivement avoir pas mal d'impact sur le standard.

--
Michael
6 7 8 9 10