OVH Cloud OVH Cloud

Qualité du compilateur C++ 5.5 de borland

41 réponses
Avatar
Seb
Bonjour,

Utilisez-vous le compilateur de Borland C++ 5.5. Je l'ai téléchargé hier et
j'avoue être énormément déçu depuis que je l'ai :-(

J'ai fait une petite recherche sous google/forums et j'ai pas vu de feed
back de cet outil.

Sébastien

10 réponses

1 2 3 4 5
Avatar
Fabien LE LEZ
On Thu, 23 Oct 2003 16:50:29 +0200, "Seb"
wrote:

C'est certes du C, mais je
voulais demander des points de vue sur le compilateur C++.


Bah oui, mais j'imagine qu'aucun lecteur de ce forum n'a écrit un tel
code, du moins pas ces dernières années...
De toutes façons, tout résultat est conforme à la norme -- y compris
un plantage.

--
http://www.giromini.org/usenet-fr/repondre.html

Avatar
Loïc Joly
Seb wrote:

"Jean-Marc Bourguet" a écrit dans le message news:


"Seb" writes:


sprintf(c, "%s%s", c, c);

Le résultat est assez stupéfiant.


Et tu t'attendais a quoi en ecrivant ce genre de choses?

(au fait, si tu fais du c, il y a fr.comp.lang.c)

A+



C'était juste un test. Je m'attendais au même résultat que génère le
compilateur IBM que j'utilise sous unix ;-) C'est certes du C, mais je
voulais demander des points de vue sur le compilateur C++.


undefined behaviour, ça veut dire que le compilo à droit de tout faire :
Planter, fonctionner comme toi tu le penses, fonctionner comme moi je le
pense, t'insulter à la compile, reformatter ton disque dur, envoyer des
lettres d'insulte à ton patron, ajouter le code source de tetris à ton
appli, dire à la CIA que c'est toi qui héberge Sadam Hussein,...


--
Loïc



Avatar
Seb
"Fabien SK" <fabsk+ a écrit dans le message news:
3f97f635$0$10401$
Seb wrote:

"Fabien SK" <fabsk+ a écrit dans le message news:
3f97e687$0$10409$

printf("before = %sn", c);
sprintf(d, "%s%s", c, c);
sprintf(c, "%s%s", c, c);
printf("after (x) = %sn", d);
printf("after = %sn", c);


sprintf(c, "%s%s", c, c);
Pas bon ! Tu écris dans un buffer dans lequel tu lis en même temps.


Le hic c'est que d'autres compilateurs réussissent ce test.


J'ai écrit ce programme. Il marche avec Visual C++ 6. Marchera-t-il avec
ton compilateur ?

#include <iostream>

int main(int argc, char *argv[])
{
int toto = 0;

*reinterpret_cast<int*>(0x0012FF7C) = 5;
std::cout << toto << std::endl;

return 0;
}



Il affiche 0 avec Borland C++ 55




Avatar
Seb
"Fabien LE LEZ" a écrit dans le message news:

On Thu, 23 Oct 2003 16:50:29 +0200, "Seb"
wrote:

C'est certes du C, mais je
voulais demander des points de vue sur le compilateur C++.


Bah oui, mais j'imagine qu'aucun lecteur de ce forum n'a écrit un tel
code, du moins pas ces dernières années...
De toutes façons, tout résultat est conforme à la norme -- y compris
un plantage.


Et bien si à partir d'un nom tu dois générer un fichier qui est dans
"NOM/NOM" : j'aurais aimé que mon sprintf(c, "%s/%s", c, c); fonctionne.
Mon résultat est "/".


Avatar
Mickael Pointier
Bah oui, mais j'imagine qu'aucun lecteur de ce forum n'a écrit un tel
code, du moins pas ces dernières années...
De toutes façons, tout résultat est conforme à la norme -- y compris
un plantage.


Et bien si à partir d'un nom tu dois générer un fichier qui est dans
"NOM/NOM" : j'aurais aimé que mon sprintf(c, "%s/%s", c, c);
fonctionne. Mon résultat est "/".


Apparement tu as du mal avec la notion de "non défini". En général c'est
bettement du au fait que préciser ce que ca doit faire obligerait
l'implémentation a faire des choses spécifiques pour gérer le problème
en question.

Il y a une page qui parle des problèmes d'écrasement dans les
différentes fonctions de la lib C:

http://wwwwbs.cs.tu-berlin.de/user-taipan/kraxel/gnuinfo/libc/Formatted_Output_Functions.html

A propos de sprintf on y lit:

"The behavior of this function is undefined if copying takes place
between objects that overlap---for example, if s is also given as an
argument to be printed under control of the `%s' conversion."

Accessoirement, tu critiques le compilateur, mais le pauvre n'y ai pour
rien là dedans, c'est dans la librairie que ca se passe.

Le problème dans ce que tu voudrais, c'est qu'il faudrait faire des
copies temporaires dans des buffers pour que tout ce passe bien, avec ce
que cela implique en problèmes divers au niveau de la taille à
allouer...

Vu que sprintf c'est un peu compliqué, on va plutôt parler de strcat. Au
'/' près, ce que tu voulais faire c'est l'équivalent de ca:

//------------------------
char c[100] = "toto";
strcat(c,c);
//------------------------

Vu que "c" vaux "toto", tu imagines normalement que concaténer C à C va
donner "totototo", exactement de la même façon qu'en BASIC C$=C$+C$ va
bien effectivement donner ce que tu recherches...

Si je vais chercher dans les sources de la lib C standard de VC6, je
trouve ca:

//------------------------
char * __cdecl strcat (
char * dst,
const char * src
)
{
char * cp = dst;
while( *cp )
cp++; /* find end of dst */
while( *cp++ = *src++ ) ; /* Copy src to end of dst */
return( dst ); /* return dst */
}
//------------------------

On a "c" qui vaut ca: toto0?????????????????

[0 => octet null / ? => octet alloué dans ton buffer / ! => octet pas
dans le buffer]

Si on passe "c" en paramètre, on a donc "cp=dst=c" et "src=c".
src => toto0????????????
cp => toto0????????????
dst => toto0????????????

Ensuite on recherche la fin de la destination, quand on à trouvé on à
ca:
src => toto0????????????
cp => 0??????????????
dst => toto0????????????

Et maintenant on copie de "src" vers "cp" jusqu'a ce qu'on ai lu un
zéro...

Itération 1:
*dst = *src (on écrit un 't')
src++
dst++

résultat fin d'itération:

src => otot????????????
cp => ??????????????
dst => totot????????????

Itération 2:
*dst = *src (on écrit un 'o')
src++
dst++

résultat fin d'itération:

src => toto????????????
cp => ??????????????
dst => tototo????????????

Itération 3:
*dst = *src (on écrit un 't')
src++
dst++

résultat fin d'itération:

src => otot????????????
cp => ??????????????
dst => tototot????????????

Itération 96:
*dst = *src (on écrit un 't')
src++
dst++

résultat fin d'itération:

src => otot!!!!
cp => ?!!!!!!!!!!!!!!!!!!!!!!
dst => totototototototototototototot...ototototototototo

En gros, à la première itération tu as explosé le '0' terminant la
chaine 'toto', donc la condition pour terminer la copie à disparu, et ca
continue très longtemps comme ca, jusqu'a ce qu'on tombe (par hasard)
sur un '0' qui traine en mémoire, ou jusqu'a ce que tu commence à tapper
en dehors de la mémoire autorisée pour ton programme et là il se produit
des choses plus ou moins dépendantes de ton systeme...

Il serait possible de faire un strcat qui n'ai pas se problème, mais il
serait monstrueusement plus lent parce qu'il faudrait parcourir la
chaine source pour trouver sa longueur et après utiliser ca comme
compteur lors de la recopie.

Mike


Avatar
kanze
"Rémy" wrote in message
news:<bn8rq8$pvm$...
"Seb" a écrit dans le message de
news:bn8pvt$orn$
"Fabien SK" <fabsk+ a écrit dans le message news:
3f97e687$0$10409$
printf("before = %sn", c);
sprintf(d, "%s%s", c, c);
sprintf(c, "%s%s", c, c);
printf("after (x) = %sn", d);
printf("after = %sn", c);


sprintf(c, "%s%s", c, c);
Pas bon ! Tu écris dans un buffer dans lequel tu lis en même temps.


Le hic c'est que d'autres compilateurs réussissent ce test.


Ca veut dire quoi "réussissent" ?

Les compilateurs Sun et Compaq donnent comme résultat "totototo" alors
que le compilateur HP donne ""...

Quel est le comportement attendu ?
Je ne pense pas que la Norme C le définisse.


En C99, c'est un comportement indéfini, parce que le premier paramètre
de sprintf a le type « char * restrict ».

Mais c'est la norme C++ qui l'intéresse, donc C90. Je n'en a
malheureusement pas une copie ici pour vérifier, mais c'est toute à fait
possible qu'elle le permet. Par inadvertance, probablement, si c'est le
cas, mais peut-être quand même.

Mais enfin, vue qu'il s'agit d'un compilateur C++, pourquoi pas écrire
simplement :

std::string c( "toto" ) ;
std::ostringstream tmp ;
tmp << c << c ;
c = tmp.str() ;

Là, on est sûr que ça marche.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16




Avatar
Seb
a écrit dans le message news:

"Rémy" wrote in message
news:<bn8rq8$pvm$...
"Seb" a écrit dans le message de
news:bn8pvt$orn$
"Fabien SK" <fabsk+ a écrit dans le message news:
3f97e687$0$10409$
printf("before = %sn", c);
sprintf(d, "%s%s", c, c);
sprintf(c, "%s%s", c, c);
printf("after (x) = %sn", d);
printf("after = %sn", c);


sprintf(c, "%s%s", c, c);
Pas bon ! Tu écris dans un buffer dans lequel tu lis en même temps.


Le hic c'est que d'autres compilateurs réussissent ce test.


Ca veut dire quoi "réussissent" ?

Les compilateurs Sun et Compaq donnent comme résultat "totototo"
alors que le compilateur HP donne ""...

Quel est le comportement attendu ?
Je ne pense pas que la Norme C le définisse.


En C99, c'est un comportement indéfini, parce que le premier paramètre
de sprintf a le type « char * restrict ».

Mais c'est la norme C++ qui l'intéresse, donc C90. Je n'en a
malheureusement pas une copie ici pour vérifier, mais c'est toute à
fait possible qu'elle le permet. Par inadvertance, probablement, si
c'est le cas, mais peut-être quand même.



Merci ,
Pouvez-vous me définir ce qu'est "char* restrict" (pour ma culture).

Mais enfin, vue qu'il s'agit d'un compilateur C++, pourquoi pas écrire
simplement :

std::string c( "toto" ) ;
std::ostringstream tmp ;
tmp << c << c ;
c = tmp.str() ;

Là, on est sûr que ça marche.


Oui bien entendu :-)





Avatar
Seb
"Mickael Pointier" a écrit dans le message
news: bnal86$5pc$
Bah oui, mais j'imagine qu'aucun lecteur de ce forum n'a écrit un
tel code, du moins pas ces dernières années...
De toutes façons, tout résultat est conforme à la norme -- y compris
un plantage.


Et bien si à partir d'un nom tu dois générer un fichier qui est dans
"NOM/NOM" : j'aurais aimé que mon sprintf(c, "%s/%s", c, c);
fonctionne. Mon résultat est "/".


Apparement tu as du mal avec la notion de "non défini". En général
c'est bettement du au fait que préciser ce que ca doit faire
obligerait l'implémentation a faire des choses spécifiques pour gérer
le problème en question.

Il y a une page qui parle des problèmes d'écrasement dans les
différentes fonctions de la lib C:


http://wwwwbs.cs.tu-berlin.de/user-taipan/kraxel/gnuinfo/libc/Formatted_Outp

ut_Functions.html

A propos de sprintf on y lit:

"The behavior of this function is undefined if copying takes place
between objects that overlap---for example, if s is also given as an
argument to be printed under control of the `%s' conversion."

Accessoirement, tu critiques le compilateur, mais le pauvre n'y ai
pour rien là dedans, c'est dans la librairie que ca se passe.



Effectivement, j'avais déjà été "trop brusque" dans mon premier post. Je
suis d'accord avec toi.

Le problème dans ce que tu voudrais, c'est qu'il faudrait faire des
copies temporaires dans des buffers pour que tout ce passe bien, avec
ce que cela implique en problèmes divers au niveau de la taille à
allouer...

Vu que sprintf c'est un peu compliqué, on va plutôt parler de strcat.
Au '/' près, ce que tu voulais faire c'est l'équivalent de ca:

//------------------------
char c[100] = "toto";
strcat(c,c);
//------------------------

Vu que "c" vaux "toto", tu imagines normalement que concaténer C à C
va donner "totototo", exactement de la même façon qu'en BASIC
C$=C$+C$ va bien effectivement donner ce que tu recherches...

Si je vais chercher dans les sources de la lib C standard de VC6, je
trouve ca:

//------------------------
char * __cdecl strcat (
char * dst,
const char * src
)
{
char * cp = dst;
while( *cp )
cp++; /* find end of dst */
while( *cp++ = *src++ ) ; /* Copy src to end of dst */
return( dst ); /* return dst */
}
//------------------------

On a "c" qui vaut ca: toto0?????????????????

[0 => octet null / ? => octet alloué dans ton buffer / ! => octet pas
dans le buffer]

Si on passe "c" en paramètre, on a donc "cp=dst=c" et "src=c".
src => toto0????????????
cp => toto0????????????
dst => toto0????????????

Ensuite on recherche la fin de la destination, quand on à trouvé on à
ca:
src => toto0????????????
cp => 0??????????????
dst => toto0????????????

Et maintenant on copie de "src" vers "cp" jusqu'a ce qu'on ai lu un
zéro...

Itération 1:
*dst = *src (on écrit un 't')
src++
dst++

résultat fin d'itération:

src => otot????????????
cp => ??????????????
dst => totot????????????

Itération 2:
*dst = *src (on écrit un 'o')
src++
dst++

résultat fin d'itération:

src => toto????????????
cp => ??????????????
dst => tototo????????????

Itération 3:
*dst = *src (on écrit un 't')
src++
dst++

résultat fin d'itération:

src => otot????????????
cp => ??????????????
dst => tototot????????????

Itération 96:
*dst = *src (on écrit un 't')
src++
dst++

résultat fin d'itération:

src => otot!!!!
cp => ?!!!!!!!!!!!!!!!!!!!!!!
dst => totototototototototototototot...ototototototototo

En gros, à la première itération tu as explosé le '0' terminant la
chaine 'toto', donc la condition pour terminer la copie à disparu, et
ca continue très longtemps comme ca, jusqu'a ce qu'on tombe (par
hasard) sur un '0' qui traine en mémoire, ou jusqu'a ce que tu
commence à tapper en dehors de la mémoire autorisée pour ton
programme et là il se produit des choses plus ou moins dépendantes de
ton systeme...

Il serait possible de faire un strcat qui n'ai pas se problème, mais
il serait monstrueusement plus lent parce qu'il faudrait parcourir la
chaine source pour trouver sa longueur et après utiliser ca comme
compteur lors de la recopie.

Mike


Je pensais naivement que le sprintf (et donc le strcat) gérait ces problèmes
: c'est très bon à savoir.

Merci :-)



Avatar
Pierre Maurette
"Seb" a écrit
[...]
Et bien si à partir d'un nom tu dois générer un fichier qui est dans
"NOM/NOM" : j'aurais aimé que mon sprintf(c, "%s/%s", c, c); fonctionne.
Mon résultat est "/".
Disons que la lib met les aérofreins, ce qui n'est pas plus idiot. Notez que

la valeur retournée est 0, ce qui est sain.
Les implantations qui donnent le "bon" résultat doivent au minimum scanner à
vide (ou appeler strlen()), et peut-être copier c dans un bouffeur. Aiutant
le faire vous-même. D'autant que ce "toto" vient bien de quelque part.
Sans le "/" : strncat(c,c,strlen(c));
Sinon :
strncat(c,strcat(c,"/"),strlen(c));
Là, ça fonctionne, mais c'est plus que bord-cadre à mon avis. Il n'est
d'après moi pas du tout certain que strlen(c) soit calculé avant
strcat(c,"/"), comme c'est le cas en C++5.5.
L = strlen(c);
strncat(c,strcat(c,"/"), L);
me semble peut-être plus fiable, puisque strcat doit être appelé avant
strncat. Les spécialistes ?
Pierre

Avatar
Laurent DELEPINE
Seb wrote:
"Fabien SK" <fabsk+ a écrit dans le message news:
3f97f635$0$10401$

Seb wrote:


"Fabien SK" <fabsk+ a écrit dans le message news:
3f97e687$0$10409$


printf("before = %sn", c);
sprintf(d, "%s%s", c, c);
sprintf(c, "%s%s", c, c);
printf("after (x) = %sn", d);
printf("after = %sn", c);


sprintf(c, "%s%s", c, c);
Pas bon ! Tu écris dans un buffer dans lequel tu lis en même temps.


Le hic c'est que d'autres compilateurs réussissent ce test.


J'ai écrit ce programme. Il marche avec Visual C++ 6. Marchera-t-il avec
ton compilateur ?

#include <iostream>

int main(int argc, char *argv[])
{
int toto = 0;

*reinterpret_cast<int*>(0x0012FF7C) = 5;
std::cout << toto << std::endl;

return 0;
}




Il affiche 0 avec Borland C++ 55


Pas normal ca. Ce devrait planter sur un veritable OS.


A+

LD





1 2 3 4 5