OVH Cloud OVH Cloud

le pbm de l'ANTISLASH

20 réponses
Avatar
david
salut

voila mon probleme :

je suis en train de développer un ptit programme (rudimentaire) en C++
de compression de données. Je l'ai d'abord ecrit sous ouindoz et
aujourd'hui, je l'ai porté sous ... LINUX (ouais, yeepeee !!)

...MAIS... BIG problem...

TOUT marche sauf un truc : à moment donné, j'ai besoin de remplacer tous
les caractères \ avec la chaine \\.

sous ouinedo, evidement ça marche...

pas sous linux. Or la compilation se passe bien... tout se passe tres
bien... sauf evidement que la recherche du caractere \ ne donne
strictement rien.

dans le détail, voila GROSSO MODO comment je procede:
(je ne remplace pas ici un cara par une chaine, mais le pbm est
EXACTEMENT le meme)

// ------------------------------------------------
char *buffer=new[_buffer_len_];

int fp=open("mon_fichier",O_RDWR,S_IREAD|S_IWRITE);
read(fp,buffer,_buffer_len_);

for (int i=0; i<_buffer_len_; i++)
{
if (buffer[i]=='\\') buffer[i]='$';
}

write(fp,buffer,_buffer_len_);
close(fp);
delete[] buffer;
// ------------------------------------------------

voila, je n'ai pas remplacé les \ par des \\, les \ par des $.
et ça ne marche pas... aucune occurence de \ n'est trouvée

ALORS ? QUELQU'UN PEUT-IL M'AIDER ??

PLEASE ?

10 réponses

1 2
Avatar
Vincent Richard

sorry, mais le code que j'ai fourni est du C++, ça n'est certes pas
du C++ typique (tableau de char, open() & compagnie)



C'est même du C++ typique. Parfois, évidemment, c'est typique parce
qu'on ne sait pas autrement. Mais d'autres fois, parce qu'il y a des
contraints externes qui l'imposent. Ne t'en fais pas ; il m'arrive
d'écrire des choses pareilles aussi.


Ce que je voulais dire c'est que ce n'est pas parce que l'on utilise
new[], delete et les commentaires de la forme // que l'on fait du C++
(je ne juge _aucunement_ les connaissances C++ de l'initiateur du fil).

D'abord, autant que je sache, il n'a pas de problème avec des tableaux
de char. C'est possible (voire probable) qu'il pourrait faire ce qu'il
veut avec vector. En revanche, je suppose que ce qu'il a posté n'est pas
son application complète, et c'est tout à fait possible qu'il y a des
choses ailleurs qui fait que std::vector ne convient pas.


En passant, je serais bien intéressé par savoir quelles sont ces choses que
ne permet pas std::vector (sérieusement, ce n'est pas ironique : je sais
bien que la STL n'est pas ce qui se fait de mieux et d'ailleurs, elle n'est
pas là pour couvrir tous les cas possibles).

Les tableaux de 'char' (et d'autres types) sont des fonctionnalités de
bas niveau que tu ne devrais pas utiliser (elles sont utilisées, entre
autres, par la bibliothèque standard (STL) pour proposer des objets de
plus haut niveau comme std::string, std::vector, etc...).


Sauf que le code qu'il a posté *est* manifestement de ce bas niveau.

[...]

Un des grands avantages de C++, c'est qu'il permet l'accès à ce niveau
quand on en a besoin.


Oui, mais il me semblait pourtant que l'utilisation de fonctions POSIX
n'était pas le sujet de ce forum (je crois que open(), read() et close() ne
sont pas dans la norme C++, s'ils le sont, alors désolé, oubliez ! :-))

Maintenant, si tu tiens absolument à programmer comme on le ferait en
C, je te suggère le groupe news:fr.comp.lang.c ...


Parce que son code ne te plaît pas, il doit aller ailleurs. Depuis quand
c'est toi qui définis les règles du groupe ?


Je n'ai aucunement parlé de règle du newsgroup. Et j'ai encore moins
défini ou imposé quoi que ce soit, ce n'est pas la peine de s'enflammer
comme ça.

Moi, j'avoue que je commence à avoir un peu marre des gens qui envoie
les autres ailleurs dès que le code ne ressemble pas à ce qu'eux ils
font en C++. Il y a des cas évident où la question est hors sujet
(comment afficher un bouton avec Windows), mais il y en a de plus en
plus où le poster est envoyé ailleurs alors que son problème est du C++,
ou est peut-être du C++.


Voir la toute dernière phrase de ce message. [*]

#include <string>
#include <fstream>
#include <iostream>
#include <string>


Deux fois <string>, mais ni <istream> ni <ostream>. Sans <istream> ni
<ostream>, ce n'est pas du C++ standard.


Typo...

int main()
{
const std::string filename = "/chemin/fichier";

// Ouverture du fichier
std::ifstream inFile(filename.c_str());


Tu pourrais expliqué pourquoi le passage par std::string ?


Peut-être parce que c'est plus facile à manipuler, et qu'on ne connaît pas
forcément le nom du fichier (peut-être une entrée utilisateur ?). Il
pourrait y avoir des lignes entre le "const ..." et le "std::ifstream ...".

Et évidemment, la sémantique de ifstream::open n'est pas celui du open
de Posix. Je suppose que s'il passe par l'open de bas niveau (plutôt que
d'utiliser des fstream ou des FILE*), c'est qu'il a besoin des
fonctionnalités qui s'y trouvent, mais qui ne se trouvent pas dans les
flux classiques. (Dans mes applications, je suis obligé à travailler à
ce niveau pour prèsque tout sauf les fichiers de log.)

if (!inFile)
{
// Traitement de l'erreur d'ouverture...
}
else
{
// Lecture du contenu
std::string data;


std::copy(std::istreambuf_iterator<std::string::value_type>(inFile),


std::istreambuf_iterator<std::string::value_type>(),
std::back_inserter(data));


Ce qui ne fait pas du tout ce qu'il a fait. Il n'a lu qu'un nombre
défini des caractères au début du fichier, non tout le fichier.


J'ai parlé de "s'inspirer" de (et donc adapter) ce code, pas de le recopier
tel quel...

Et franchement, écrire std::string::value_type à la place de char, c'est
de la masturbation mentale, ou de la complexité pour obfusquée.


Je pense plutôt que c'est de la rigueur, mais chacun ses avis.

for ( ; (i = data.find(find, i)) != std::string::npos ; )


Juste curieux, mais pourquoi « for » et non « while » ici ?


Une préférence, tout simplement !
Qui a dit "obfuscation" ? :-)

{
data.replace(i, find.length(), replace);
i += replace.length();
}


Son problème se situait à un niveau beaucoup plus bas. Et j'aimerais
bien voir la performance de ta solution avec un fichier qui consiste en
une million de ''.


J'ai toujours respecté le principe qu'il vaut mieux un programme fiable
mais lent (et qui fait ce qu'on veut) qu'un programme "rapide" (relatif)
mais qui plante.

Après, si besoin en optimisation il y a, alors on optimise.

De toutes les façons, l'initiateur du fil ne parlait aucunement d'impératif
de rapidité dans son message.

En général, sa solution est préférable à la tienne. Mais dans
l'ensemble, je n'essaierais pas une transformation en place.


Ma solution a tout de même l'avantage d'être plus portable (et donc
elle fonctionnerait vraisemblablement sous les 2 systèmes qu'il essaye
de viser).

// Ouverture du fichier en écriture
std::ofstream outFile(filename.c_str());

if (!outFile)
{
// Traitement de l'erreur d'ouverture...


Tu ésquisses le seul aspect intéressant. Qu'est-ce que tu fais si
l'ouverture échoue ici ?


L'initiateur du fil n'a pas précisé ce cas, je ne peux pas l'inventer !

D'ailleurs, dans son message, il n'y a également _aucune_ gestion des
erreurs (bien sûr, il a dit que c'était une version simplifié). Cependant,
ce n'était pas le sujet du problème.

En fait, mon commentaire sur les transformations « en place » vaut
double ici ; j'écrirais les données en sortie dans un fichier
temporaire, et seulement lors que tout c'est bien passé, je supprimerais
le fichier initial, et je rénommerais le fichier temporaire.


Je suis également d'accord avec ce principe.

Mais ce n'est apparement pas ce qu'il voulait faire. Ma solution "colle"
donc plus à son idée de départ.

Et la gestion des erreurs ?

[...]

Et le return ? Tu ne veux sûrement pas renvoyer 0 s'il y a eu une
erreur.


Idem...

Dans l'ensemble, son essai me semblait aussi bon, sinon mieux que le
tien.


Sauf que mon compilateur ne connaît pas les fonction read() et open()
avec les seules inclusions standards... ;-)

[*] Ce qui est amusant, c'est qu'il y a déjà eu des personnes ici-même qui
se sont vues redirigées sur news:fr.comp.os.unix ou fcomp pour moins que ça.

PS : je n'ai rien contre toi David ! :-)

Vincent

--
vmime, une bibliothèque C++ sous licence GPL pour parser et générer
des messages au format MIME : http://www.sourceforge.net/projects/vmime/



Avatar
Jean-Marc Bourguet
Vincent Richard writes:

[*] Ce qui est amusant, c'est qu'il y a déjà eu des personnes ici-même qui
se sont vues redirigées sur news:fr.comp.os.unix ou fcomp pour moins que ça.




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
david
j'invite les personnes interressées à lire
news://news.free.fr:119/
ou j'explique que, oui le code que j'ai fourni,n'avait rien à voir avec
mon pbm

enfin, une version(alpha) windows de jscomp est dispo sur mon site:
http://www.frontere.org/index.html?MenuClick(3,2);
le pbm que j'ai rencontré touche l'adaptation du code sous Linux
mais il semble que son origine vienne de ce que des lignes (2 sur
plusieurs milliers) aient été ignorées par le compilateur (g++)...
or le code d'origine etait au format txt DOS càd avec les CR LF : peut
etre une piste.

le pbm à finallement ete resolu.

qd au programme il n'est encore qu'a 1/3 de son developpement.

et il est ecrit en C++ !!
Avatar
david
Jean-Marc Bourguet wrote:

Et aussi a cross-poster plutot que multiposter (ou mieux encore pour
cet exemple, te contenter de fr.comp.os.unix).

A+



j'esperais : + de mails = + efficacité... mais ça a vraiment raté. la
faute à moi.

Avatar
kanze
Vincent Richard wrote
in message news:<3fa7cf3c$0$27031$...

sorry, mais le code que j'ai fourni est du C++, ça n'est certes
pas du C++ typique (tableau de char, open() & compagnie)



C'est même du C++ typique. Parfois, évidemment, c'est typique parce
qu'on ne sait pas autrement. Mais d'autres fois, parce qu'il y a des
contraints externes qui l'imposent. Ne t'en fais pas ; il m'arrive
d'écrire des choses pareilles aussi.


Ce que je voulais dire c'est que ce n'est pas parce que l'on utilise
new[], delete et les commentaires de la forme // que l'on fait du C++
(je ne juge _aucunement_ les connaissances C++ de l'initiateur du
fil).


Et si ce n'est pas du C++, c'est quoi, alors ? Il y a beaucoup de façons
à utiliser le C++. Sans savoir toutes ces contraintes, je suis incapable
à dire quelle est la façon qui lui convient le plus.

D'abord, autant que je sache, il n'a pas de problème avec des
tableaux de char. C'est possible (voire probable) qu'il pourrait
faire ce qu'il veut avec vector. En revanche, je suppose que ce
qu'il a posté n'est pas son application complète, et c'est tout à
fait possible qu'il y a des choses ailleurs qui fait que std::vector
ne convient pas.


En passant, je serais bien intéressé par savoir quelles sont ces
choses que ne permet pas std::vector (sérieusement, ce n'est pas
ironique : je sais bien que la STL n'est pas ce qui se fait de mieux
et d'ailleurs, elle n'est pas là pour couvrir tous les cas possibles).


Beaucoup. Le plus évident, évidemment, c'est quand tu dois supporter un
compilateur ancient qui ne l'a pas:-).

Autrement, quand il faut passer le tableau (y compris la responsabilité
de l'effacement) à une fonction qui s'attend à un T*. On ne peut se
servir de std::vector dans ce cas QUE si la durée de vie qu'il donne
convient -- c'est souvent le cas, mais pas forcement toujours.

Un autre cas, c'est l'implémentation des choses de très bas niveau. Si
c'est évident qu'on ne peut pas se servir de std::vector dans
l'implémentation de std::vector, je le vois mal aussi dans
l'implémentation de std::string. Et je n'exclurais pas d'office qu'il y
a des classes semblables propre à l'application.

Finalement, il y a des cas où c'est simplement trop lourd -- considère
quelque chose du genre :

class Point3D
{
public:
// ...
private:
double myCoords[ 3 ] ;
} ;

Tu ne vas pas me dire que tu utiliserais std::vector ici. Surtout si tu
risques d'avoir des tableaux avec des milliers, voire des millions de
Point3D.

Les tableaux de 'char' (et d'autres types) sont des fonctionnalités
de bas niveau que tu ne devrais pas utiliser (elles sont utilisées,
entre autres, par la bibliothèque standard (STL) pour proposer des
objets de plus haut niveau comme std::string, std::vector, etc...).


Sauf que le code qu'il a posté *est* manifestement de ce bas niveau.

[...]

Un des grands avantages de C++, c'est qu'il permet l'accès à ce
niveau quand on en a besoin.


Oui, mais il me semblait pourtant que l'utilisation de fonctions POSIX
n'était pas le sujet de ce forum (je crois que open(), read() et
close() ne sont pas dans la norme C++, s'ils le sont, alors désolé,
oubliez ! :-))


Tout à fait. Mais d'après sa formulation de la question, ce n'est pas du
tout évident que ce soit les fonctions Posix en question. Il parlait
surtout du traitement de '', ce qui est réelement un problème C++.

En plus, évidemment, les fonctions dont il s'est servi ont leur
contrepartie dans tous les systèmes d'exploitation. Si les problèmes
particuliers à l'API Posix sont hors sujet ici, l'enchaînement des
fonctions qui sont généralement disponibles, et qui ont leur
contrepartie dans la norme, l'est.

Maintenant, si tu tiens absolument à programmer comme on le ferait
en C, je te suggère le groupe news:fr.comp.lang.c ...


Parce que son code ne te plaît pas, il doit aller ailleurs. Depuis
quand c'est toi qui définis les règles du groupe ?


Je n'ai aucunement parlé de règle du newsgroup. Et j'ai encore moins
défini ou imposé quoi que ce soit, ce n'est pas la peine de
s'enflammer comme ça.


Je ne te vise pas particulièrement, mais je constate depuis un certain
temps que certains passent plus de temps à essayer à signaler des hors
sujets que de faire des contributions constructives. Or, s'il y a bien
des cas où l'intervention est justifiée -- moi, non plus, je ne veux pas
voir 90% des postes traiter des questions du genre « comment positionner
un bouton dans une boîte de dialogue Windows », je trouve qu'il y a
exagération. On ne doit répondre avec les hors sujets que dans le cas où
c'est 100% sûr et manifeste -- si une question du genre « comment mettre
du texte dans une boîte de dialogue » est 100% hors sujet, une question
du genre « comment formatter du texte pour le mettre dans une boîte de
dialogue » est, à mon avis, tout à fait acceptable, même s'il y a boîte
de dialogue.

En plus, je constate une tendance à insister que tout ce qui ne fait pas
un usage exagéré de la STL n'est pas du C++, ce qui est carrément faux.
La STL est une partie du C++, mais ce n'est pas le tout -- et printf est
aussi une partie du C++. Selon l'application, il peut y avoir bien de
raisons pour ne pas utiliser toutes les nouveautés.

Moi, j'avoue que je commence à avoir un peu marre des gens qui
envoie les autres ailleurs dès que le code ne ressemble pas à ce
qu'eux ils font en C++. Il y a des cas évident où la question est
hors sujet (comment afficher un bouton avec Windows), mais il y en a
de plus en plus où le poster est envoyé ailleurs alors que son
problème est du C++, ou est peut-être du C++.


Voir la toute dernière phrase de ce message. [*]

#include <string>
#include <fstream>
#include <iostream>
#include <string>


Deux fois <string>, mais ni <istream> ni <ostream>. Sans <istream>
ni <ostream>, ce n'est pas du C++ standard.


Typo...


D'accord. En ce qui concerne la duplication de <string>, je m'en doutais
un peu. Mais je vois très souvent des postes avec #include <iostream>,
mais sans le <istream> ou le <ostream>.

En passant, tu as aussi oublié <iterator> et <algorithm>.

int main()
{
const std::string filename = "/chemin/fichier";

// Ouverture du fichier
std::ifstream inFile(filename.c_str());


Tu pourrais expliqué pourquoi le passage par std::string ?


Peut-être parce que c'est plus facile à manipuler, et qu'on ne connaît
pas forcément le nom du fichier (peut-être une entrée utilisateur ?).
Il pourrait y avoir des lignes entre le "const ..." et le
"std::ifstream ...".


C'est plus facile à manipuler, quand on a à manipuler. Ici, on a une
constante, de type « char const[] », et il nous faut un « char const* ».
L'introduction de std::string me semble de la complexité pour rien.

C'est sûr que *SI* il y avait d'autre traitement... Mais il y a toujours

std::ifstream inFile( "/chemin/fichier" ) ;

Et évidemment, la sémantique de ifstream::open n'est pas celui du
open de Posix. Je suppose que s'il passe par l'open de bas niveau
(plutôt que d'utiliser des fstream ou des FILE*), c'est qu'il a
besoin des fonctionnalités qui s'y trouvent, mais qui ne se trouvent
pas dans les flux classiques. (Dans mes applications, je suis obligé
à travailler à ce niveau pour prèsque tout sauf les fichiers de
log.)

if (!inFile)
{
// Traitement de l'erreur d'ouverture...
}
else
{
// Lecture du contenu
std::string data;

std::copy(std::istreambuf_iterator<std::string::value_type>(inFile),
std::istreambuf_iterator<std::string::value_type>(),
std::back_inserter(data));


Ce qui ne fait pas du tout ce qu'il a fait. Il n'a lu qu'un nombre
défini des caractères au début du fichier, non tout le fichier.


J'ai parlé de "s'inspirer" de (et donc adapter) ce code, pas de le
recopier tel quel...


Malheureusement, les itérateurs de stream se prête très mal à ce genre
d'adaptation. Et l'idiome de deux itérateurs rend l'implémentation d'un
itérateur d'adaptation difficile. Alors, si tu as d'autres outils sous
la main, que tu connais bien, du genre des adaptateurs d'itérateur de
Boost, ou la charpente des streambuf filtrant pour limiter ce que voit
l'itérateur, bien. Mais sinon, tu as plus vite fait d'écrire une boucle
à la main.

Le but, ce n'est pas d'utiliser la technologie pour rouler la mécanique.
Le but, c'est de faire un programme qui marche, et c'est la technologie
qui doit être asservie à ce but, et non l'inverse.

Et franchement, écrire std::string::value_type à la place de char,
c'est de la masturbation mentale, ou de la complexité pour
obfusquée.


Je pense plutôt que c'est de la rigueur, mais chacun ses avis.

for ( ; (i = data.find(find, i)) != std::string::npos ; )


Juste curieux, mais pourquoi « for » et non « while » ici ?


Une préférence, tout simplement !


J'ai aussi une forte préférence pour les for, afin de régrouper tout le
contrôle de la boucle en tête. Mais de là à utiliser un for sans
initialisation ET sans mise à jour.

En fait, j'aurais bien écrit la boucle avec un for :

for ( int i = data.find( find, 0 ) ;
i != std::string::npos ;
i = data.find( find, i ) )

Qui a dit "obfuscation" ? :-)


C'est de l'obfuscation de cacher une modification d'état dans
l'intérieur d'une condition. (C'est aussi interdit par toutes les règles
de programmation que je connais.)

{
data.replace(i, find.length(), replace);
i += replace.length();
}


Son problème se situait à un niveau beaucoup plus bas. Et j'aimerais
bien voir la performance de ta solution avec un fichier qui consiste
en une million de ''.


J'ai toujours respecté le principe qu'il vaut mieux un programme
fiable mais lent (et qui fait ce qu'on veut) qu'un programme "rapide"
(relatif) mais qui plante.


Le problème, c'est qu'avec un million de '', ton programme risque fort
de planter. Je ne vois pas de bloc de try pour traiter le bad_alloc qui
risque de se produire.

Sans considérations de performance, la solution la plus sûre et la plus
évidente est simplement :

for ( int ch = inFile.get() ; ch != EOF ; ch = inFile.get() ) {
if ( ch == '' ) {
outFile.put( '' ) ;
outFile.put( '' ) ;
} else {
outFile.put( ch ) ;
}
}

C'est d'ailleurs sûrement comment je l'écrirais dans la pratique.

Après, si besoin en optimisation il y a, alors on optimise.


Vouloir pouvoir traiter des fichiers qui ne se tiennent pas dans la
mémoire, ce n'est pas de l'optimisation -- c'est de la programmation
défensive.

De toutes les façons, l'initiateur du fil ne parlait aucunement
d'impératif de rapidité dans son message.


Et moi non plus, je ne parle pas de la rapidité. Le mot « performance »
a été mal choisi.

Ceci dit, il y a des considérations de performance qui ne s'attend pas.
Si je dois trier des données que je lis d'un fichier, et pour une raison
quelconque, je ne peux pas me servir de std::sort, je ne vais pas
implémenter un tri par insertion. Tu as choisi une implémentation qui
est potentiellement O(n^2) sur la taille des données.

Un programme qui ne termine pas n'est pas correct (à condition,
évidemment, que le programme ne traite qu'une quantité finie de données.
Mes serveurs ne termine jamais, parce qu'ils reçoivent constamment de
nouvelles requêtes à traiter).

En général, sa solution est préférable à la tienne. Mais dans
l'ensemble, je n'essaierais pas une transformation en place.


Ma solution a tout de même l'avantage d'être plus portable (et donc
elle fonctionnerait vraisemblablement sous les 2 systèmes qu'il essaye
de viser).


Portable est rélative. Elle ne fonctionne pas dans l'environement de
production où je travaille. Je pourrais imaginer qu'elle pose aussi des
problèmes à un certain compilateur Windows, qui n'est pas
particulièrement fort en ce qui concerne les templates.

Ceci dit, au moins tu as eu le bon sens à éviter la solution STL
classique :

std::string data( (std::istreambuf_iterator< char >)( inFile ) ,
(std::istreambuf_iterator< char >)() ) ;

Solution qui pose réelement des problèmes de templates, avec beaucoup de
compilateurs courants.

Mais note bien qu'il y a deux questions indépendantes : comment formuler
l'algorithme, et le choix des entrées/sorties. Je suis bien d'accord que
quand on peut, il vaut mieux se servir des iostream, sinon les FILE*, et
seulement en dernière ligne les entrées/sorties du système. N'empêche
que les garanties données par la norme pour les iostream et les FILE ne
suffisent que rarement, et que pour tout ce qui est critique, on est
obligé à passer par les requêtes Posix.

Quant à l'algorithme de traitement, franchement, je trouve la simple
boucle caractère par caractère bien plus simple que tout ce qu'offre la
STL.

// Ouverture du fichier en écriture
std::ofstream outFile(filename.c_str());

if (!outFile)
{
// Traitement de l'erreur d'ouverture...


Tu ésquisses le seul aspect intéressant. Qu'est-ce que tu fais si
l'ouverture échoue ici ?


L'initiateur du fil n'a pas précisé ce cas, je ne peux pas l'inventer !


Mais tu essaies à montrer quelque chose de mieux, non ?

En fait, évidemment, il y a un minimum, et ici, on touche à un aspect
qu'il avait mal traité aussi. Il y a deux problèmes en cas d'erreur dans
vos implémentations : vous laissez un fichier corrompu, tout en ayant
detruit le fichier avec les données initiales, et vous ne signalez
nullement l'erreur lors du retour du programme, ce qui fait que le
programme ne peut pas servir dans un script.

D'ailleurs, dans son message, il n'y a également _aucune_ gestion des
erreurs (bien sûr, il a dit que c'était une version simplifié).
Cependant, ce n'était pas le sujet du problème.


Peut-être, mais tu prétends montrer un programme complet.

En fait, mon commentaire sur les transformations « en place » vaut
double ici ; j'écrirais les données en sortie dans un fichier
temporaire, et seulement lors que tout c'est bien passé, je
supprimerais le fichier initial, et je rénommerais le fichier
temporaire.


Je suis également d'accord avec ce principe.

Mais ce n'est apparement pas ce qu'il voulait faire. Ma solution
"colle" donc plus à son idée de départ.


Mais son idée du départ ne marche pas. Lui, il s'est égaré un peu, avec
la transformation de '' en '?' (qui pourrait à la rigueur se faire sur
place). Toi, tu as attaqué au problème initial, transformer les '' en
"\". Ce qui est tout à ton crédit. Seulement, pour ce problème, il
n'y a pas de solution générale sur place ; il faut impérativement passer
par un fichier temporaire.

Et la gestion des erreurs ?

[...]

Et le return ? Tu ne veux sûrement pas renvoyer 0 s'il y a eu une
erreur.


Idem...


À la différence près qu'il disait que son programme ne marchait pas, et
que tu dis que le tien marche.

Dans l'ensemble, son essai me semblait aussi bon, sinon mieux que le
tien.


Sauf que mon compilateur ne connaît pas les fonction read() et open()
avec les seules inclusions standards... ;-)


Mais ce n'est pas un aspect important de sa solution. Et dans la
pratique, on ne peut pas écrire une application utile avec les seules
inclusions standards.

[*] Ce qui est amusant, c'est qu'il y a déjà eu des personnes ici-même
qui se sont vues redirigées sur news:fr.comp.os.unix ou fcomp pour
moins que ça.


Certes. C'est un peu pourquoi je me suis trouvé si dur avec toi. Qu'on
signale des hors sujets flagrants, je veux bien, mais qu'on jette des
gens pour un oui ou un non, ça ne va pas.

Mais surtout, tu as insisté que ce qu'il écrit n'était pas du C++. C'est
un C++. Ce n'est peut-être pas la façon qui convient la plus à résoudre
son problème, mais je voulais simplement démontrer que l'utilisation des
moyens les plus exotique du langage ne garantissait pas un bon programme
non plus.

Pour ce qu'il vaut, voilà ce que je propose pour ce que tu as écrit. Ce
n'est pas comment je l'aurais écrit dans la réalité -- j'ai pas mal des
fonctions bibliothèques déjà disponible, et je me serais servi sûrement
de GB_ProgramStatus, et probablement de GB_CommandLine et d'autres. Mais
c'est du C++, même si je ne me sers en rien de la STL.

Tout commentaire est bien venu.

#ifndef OLD
#include <iostream>
#include <istream>
#include <ostream>
#include <fstream>
#else
#include <iostream.h>
#include <fstream.h>
#define std
#endif
#include <string>
#include <stdio.h>
#include <stdlib.h>

static int returnCode = EXIT_SUCCESS ;
static char* progName = NULL ;

void
process( std::istream& in, std::ostream& out )
{
int ch = in.get() ;
while ( ch != EOF ) {
switch ( ch ) {
case '' :
out.put( '' ) ;
out.put( '' ) ;
break ;

default :
out.put( static_cast< char >( ch ) ) ;
break ;
}
ch = in.get() ;
}
}

void
processWithTemp( std::string const& filename )
{
std::string tmpName( filename + ".bak" ) ;
if ( rename( filename.c_str(), tmpName.c_str() ) != 0 ) {
std::cerr << progName << ": cannot rename to " << tmpName << 'n' ;
returnCode = EXIT_FAILURE ;
} else {
std::ofstream out( filename.c_str() ) ;
if ( ! out ) {
std::cerr << progName << ": cannot create new file "
<< filename << ", data in "
<< tmpName << 'n' ;
throw EXIT_FAILURE ;
}
std::ifstream in( tmpName.c_str() ) ;
if ( ! in ) {
std::cerr << progName << ": cannot open renamed file "
<< tmpName << 'n' ;
throw EXIT_FAILURE ;
}
process( in, out ) ;
if ( ! out ) {
std::cerr << progName << ": write error in " << filename << 'n' ;
std::cerr << " Old data in " << tmpName << 'n' ;
throw EXIT_FAILURE ;
}
remove( tmpName.c_str() ) ;
}
}

int
main( int argc, char** argv )
{
try {
progName = argv[ 0 ] ;
if ( argc > 1 ) {
for ( int i = 1 ; i < argc ; ++ i ) {
processWithTemp( argv[ i ] ) ;
}
} else {
process( std::cin, std::cout ) ;
std::cout.flush() ;
if ( ! std::cout ) {
std::cerr << progName
<< ": write error on standard out" << 'n' ;
throw EXIT_FAILURE ;
}
}
} catch ( int errorCode ) {
returnCode = errorCode ;
}
return returnCode ;
}

--
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
Vincent Richard

Vincent Richard wrote
in message news:<3fa7cf3c$0$27031$...


sorry, mais le code que j'ai fourni est du C++, ça n'est certes
pas du C++ typique (tableau de char, open() & compagnie)



C'est même du C++ typique. Parfois, évidemment, c'est typique parce
qu'on ne sait pas autrement. Mais d'autres fois, parce qu'il y a des
contraints externes qui l'imposent. Ne t'en fais pas ; il m'arrive
d'écrire des choses pareilles aussi.


Ce que je voulais dire c'est que ce n'est pas parce que l'on utilise
new[], delete et les commentaires de la forme // que l'on fait du C++
(je ne juge _aucunement_ les connaissances C++ de l'initiateur du
fil).


Et si ce n'est pas du C++, c'est quoi, alors ? Il y a beaucoup de façons
à utiliser le C++. Sans savoir toutes ces contraintes, je suis incapable
à dire quelle est la façon qui lui convient le plus.


C'est bien du C++, mais pas dans le sens où je l'entendais : dans mes
projets, je m'efforce d'utiliser le plus possible la STL car elle est (en
théorie) portable, et très efficace (bien optimisée par les développeurs de
compilateurs), donc pourquoi vouloir réinventer la roue à chaque fois ?
Sauf évidemment, comme tu l'as dis, qu'il y peut y avoir des contraintes
que l'on ne connaît pas, et comme je ne les connais pas non plus, j'ai
proposé l'utilisation de la STL...

En passant, je serais bien intéressé par savoir quelles sont ces
choses que ne permet pas std::vector (sérieusement, ce n'est pas
ironique : je sais bien que la STL n'est pas ce qui se fait de mieux
et d'ailleurs, elle n'est pas là pour couvrir tous les cas possibles).


Beaucoup. Le plus évident, évidemment, c'est quand tu dois supporter un
compilateur ancient qui ne l'a pas:-).

Autrement, quand il faut passer le tableau (y compris la responsabilité
de l'effacement) à une fonction qui s'attend à un T*. On ne peut se
servir de std::vector dans ce cas QUE si la durée de vie qu'il donne
convient -- c'est souvent le cas, mais pas forcement toujours.

Un autre cas, c'est l'implémentation des choses de très bas niveau. Si
c'est évident qu'on ne peut pas se servir de std::vector dans
l'implémentation de std::vector, je le vois mal aussi dans
l'implémentation de std::string. Et je n'exclurais pas d'office qu'il y
a des classes semblables propre à l'application.

Finalement, il y a des cas où c'est simplement trop lourd -- considère
quelque chose du genre :


Merci pour ces explications.

Les tableaux de 'char' (et d'autres types) sont des fonctionnalités
de bas niveau que tu ne devrais pas utiliser (elles sont utilisées,
entre autres, par la bibliothèque standard (STL) pour proposer des
objets de plus haut niveau comme std::string, std::vector, etc...).


Sauf que le code qu'il a posté *est* manifestement de ce bas niveau.




Et ma vrai question était : "est-ce vraiment la peine de passer à un niveau
aussi bas pour faire ce qu'il veut faire ?".

Maintenant, il faut peser le pour et le contre, selon ce qu'il veut comme
portabilité/fonctionnalité/performance. Et encore une fois, j'insiste, il
n'en a fait aucunement mention dans son message.

Maintenant, si tu tiens absolument à programmer comme on le ferait
en C, je te suggère le groupe news:fr.comp.lang.c ...


Parce que son code ne te plaît pas, il doit aller ailleurs. Depuis
quand c'est toi qui définis les règles du groupe ?


Je n'ai aucunement parlé de règle du newsgroup. Et j'ai encore moins
défini ou imposé quoi que ce soit, ce n'est pas la peine de
s'enflammer comme ça.


Je ne te vise pas particulièrement, mais je constate depuis un certain
temps que certains passent plus de temps à essayer à signaler des hors
sujets que de faire des contributions constructives.


Malheureusement, on constate aussi qu'il y a de plus en plus de messages HS
et aussi de personnes qui ne consultent pas les chartes des groupes avant
d'y poster.

#include <string>
#include <fstream>
#include <iostream>
#include <string>


Deux fois <string>, mais ni <istream> ni <ostream>. Sans <istream>
ni <ostream>, ce n'est pas du C++ standard.


Typo...


D'accord. En ce qui concerne la duplication de <string>, je m'en doutais
un peu. Mais je vois très souvent des postes avec #include <iostream>,
mais sans le <istream> ou le <ostream>.


Oui, en effet (surtout qu'il me semble que c'est grâce à un de tes posts que
j'avais appris ça).

En passant, tu as aussi oublié <iterator> et <algorithm>.


D'ailleurs, c'est tout de même assez embêtant que mon compilateur (g++ 3.2.2
/ Linux) ne me fasse pas part de ces problèmes d'inclusion... Si quelqu'un
a la solution (j'utilise pourtant les flags -ansi -pedantic -Wall).

La norme impose-t-elle que le programme ne doit pas compiler ou bien elle
impose seulement que si ces inclusions ne sont pas présentes, alors le
programme "a le droit" de ne pas fonctionner ?

Ma solution a tout de même l'avantage d'être plus portable (et donc
elle fonctionnerait vraisemblablement sous les 2 systèmes qu'il essaye
de viser).


Portable est rélative. Elle ne fonctionne pas dans l'environement de
production où je travaille.


Je parlais d'une portabilitié vis-à-vis de la norme donc théorique, et non
pratique. Ah, si tous les compilateurs respectaient la norme à 100% ! :-)

Mais note bien qu'il y a deux questions indépendantes : comment formuler
l'algorithme, et le choix des entrées/sorties. Je suis bien d'accord que
quand on peut, il vaut mieux se servir des iostream, sinon les FILE*, et
seulement en dernière ligne les entrées/sorties du système. N'empêche
que les garanties données par la norme pour les iostream et les FILE ne
suffisent que rarement, et que pour tout ce qui est critique, on est
obligé à passer par les requêtes Posix.


Bon, en fait, j'admets que je suis un peu de mauvaise foi car dans la
plupart de mes projets, je ne me sers pas des iostream...

Sauf que mon compilateur ne connaît pas les fonction read() et open()
avec les seules inclusions standards... ;-)


Mais ce n'est pas un aspect important de sa solution. Et dans la
pratique, on ne peut pas écrire une application utile avec les seules
inclusions standards.


Tout à fait d'accord, mais dans ce cas là en parler ici est donc HS.

Vincent

--
vmime, une bibliothèque C++ sous licence GPL pour parser et générer
des messages au format MIME : http://www.sourceforge.net/projects/vmime/





Avatar
kanze
Vincent Richard wrote
in message news:<3fa8ec7b$0$10432$...

Vincent Richard
wrote in message news:<3fa7cf3c$0$27031$...



[...]
Ce que je voulais dire c'est que ce n'est pas parce que l'on
utilise new[], delete et les commentaires de la forme // que l'on
fait du C++ (je ne juge _aucunement_ les connaissances C++ de
l'initiateur du fil).


Et si ce n'est pas du C++, c'est quoi, alors ? Il y a beaucoup de
façons à utiliser le C++. Sans savoir toutes ces contraintes, je
suis incapable à dire quelle est la façon qui lui convient le plus.


C'est bien du C++, mais pas dans le sens où je l'entendais : dans mes
^^


Et c'est précisement ça que je te réproche. De vouloir imposer le sens
que TU l'entends à tout le monde, en disant que ce n'est pas du C++, et
qu'il doit aller ailleurs.

La véritable force de C++, c'est précisement que c'est beaucoup de
langages en un. Je m'en sers pour l'expérimentation à outrance à titre
personnel, et je m'en sers pour des applications ultra-robuste et
ultra-maintenable, où il faut absolument se restreindre à des techniques
éprouvées. J'apprécie la possibilité de passer de l'un à l'autre sans
changer de langage.

Dans certaines applications professionnelles, je ne me sers pas toujours
de la STL, pour diverses raisons. Et dans aucune application
professionnelle je ne me sers des éléments « avancés » de la STL, comme
les itérateurs de flux.

projets, je m'efforce d'utiliser le plus possible la STL car elle est
(en théorie) portable, et très efficace (bien optimisée par les
développeurs de compilateurs), donc pourquoi vouloir réinventer la
roue à chaque fois ?


Parce qu'en ce qui concerne la portabilité, la théorie ne rejoint pas la
pratique. La STL fournie avec VC++ 6.0 est tout à fait autre chose que
celle fournie avec g++ 2.95.2, et Sun CC 5.1 n'en a même pas en mode
compat=4. Et ce sont les trois compilateurs que j'utilise
professionnellement actuellement -- on a porté un petit bout de la STL
de CGI au Sun CC, de façon à pouvoir commencer à utiliser std::vector et
std::string à la place des éléments maison, mais ça s'arrête là.

Mais ce n'est pas pour autant que je ne fais pas de C++.

Sauf évidemment, comme tu l'as dis, qu'il y peut y avoir des
contraintes que l'on ne connaît pas, et comme je ne les connais pas
non plus, j'ai proposé l'utilisation de la STL...


La proposer, c'est bien. Dire que ce n'est pas du C++ parce qu'il ne
s'en sert pas, non. Moi aussi, je dirais que typiquement, si on a besoin
d'un tableau, on préfèrerait std::vector. Mais je ne dirais pas que T[]
n'est pas du C++.

[...]
Sauf que le code qu'il a posté *est* manifestement de ce bas
niveau.




Et ma vrai question était : "est-ce vraiment la peine de passer à un
niveau aussi bas pour faire ce qu'il veut faire ?".


Présenté comme ça, je suis d'accord avec toi.

Maintenant, il faut peser le pour et le contre, selon ce qu'il veut
comme portabilité/fonctionnalité/performance. Et encore une fois,
j'insiste, il n'en a fait aucunement mention dans son message.


Je le sais, et je suis tout à fait d'accord avec l'idée de présenter des
alternatifs plus évolués. Mais ça n'empêche pas que ce qu'il fait, c'est
aussi du C++, et que ça se dicute ici aussi.

Maintenant, si tu tiens absolument à programmer comme on le
ferait en C, je te suggère le groupe news:fr.comp.lang.c ...


Parce que son code ne te plaît pas, il doit aller
ailleurs. Depuis quand c'est toi qui définis les règles du groupe
?


Je n'ai aucunement parlé de règle du newsgroup. Et j'ai encore moins
défini ou imposé quoi que ce soit, ce n'est pas la peine de
s'enflammer comme ça.


Je ne te vise pas particulièrement, mais je constate depuis un
certain temps que certains passent plus de temps à essayer à
signaler des hors sujets que de faire des contributions
constructives.


Malheureusement, on constate aussi qu'il y a de plus en plus de
messages HS et aussi de personnes qui ne consultent pas les chartes
des groupes avant d'y poster.


Je ne trouve pas que le nombre en ait augmenté ce dernier temps. Il y en
a toujours un peu, mais à mon avis, ça reste dans les limites
acceptables.

#include <string>
#include <fstream>
#include <iostream>
#include <string>


Deux fois <string>, mais ni <istream> ni <ostream>. Sans
<istream> ni <ostream>, ce n'est pas du C++ standard.


Typo...


D'accord. En ce qui concerne la duplication de <string>, je m'en
doutais un peu. Mais je vois très souvent des postes avec #include
<iostream>, mais sans le <istream> ou le <ostream>.


Oui, en effet (surtout qu'il me semble que c'est grâce à un de tes
posts que j'avais appris ça).


Malheureusement, c'est assez peu réconnu. C'est pourquoi je ne manque
pas de le dire quand l'occasion se présente.

En passant, tu as aussi oublié <iterator> et <algorithm>.


D'ailleurs, c'est tout de même assez embêtant que mon compilateur (g++
3.2.2 / Linux) ne me fasse pas part de ces problèmes d'inclusion... Si
quelqu'un a la solution (j'utilise pourtant les flags -ansi -pedantic
-Wall).

La norme impose-t-elle que le programme ne doit pas compiler ou bien
elle impose seulement que si ces inclusions ne sont pas présentes,
alors le programme "a le droit" de ne pas fonctionner ?


La norme C++ dit que n'importe quel en-tête standard peut inclure
n'importe quel autre. Donc, si tu fais « #include <vector> », tu peux
n'avoir que std::vector, tu peux avoir toute la bibliothèque, ou tu peux
avoir quelque chose entre les deux.

La norme C était bien plus précise à cet égard. C'est dommange que ce
n'est pas le cas en C++, d'autant plus que la présence ou l'absense d'un
en-tête peu jouer sur l'ensemble des fonctions considérées lors d'un
surcharge -- l'oublie d'un en-tête dont tu as formellement besoin peut
donner simplement une différence dans la sémantique du programme, et non
une erreur de compilation.

--
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
Marc Boyer
wrote:
Vincent Richard wrote
in message news:<3fa8ec7b$0$10432$...

Vincent Richard
wrote in message news:<3fa7cf3c$0$27031$...
C'est bien du C++, mais pas dans le sens où je l'entendais : dans mes

^^

Et c'est précisement ça que je te réproche. De vouloir imposer le sens
que TU l'entends à tout le monde, en disant que ce n'est pas du C++, et
qu'il doit aller ailleurs.


Pour argumenter encore plus dans ton sens, je souligne que Stroustrup
lui même considère qu'un des principes fondateurs de C++, c'est qu'on
peut l'apprendre "progressivement", découvrir les méchanismes
d'abstraction peu à peu.

Et Herb Sutter insiste bien sur le fait de ne pas écrire du
code qu'on ne maîtrise pas, et propose un ratio 90%/10% entre
ce qu'on maîtrise et les choses qu'on découvre.

Marc Boyer
--
Lying for having sex or lying for making war? Trust US presidents :-(



Avatar
kanze
Marc Boyer wrote in message
news:<bocv9q$k3m$...

Et Herb Sutter insiste bien sur le fait de ne pas écrire du code
qu'on ne maîtrise pas, et propose un ratio 90%/10% entre ce qu'on
maîtrise et les choses qu'on découvre.


Tu peux m'indiquer une citation ?

Bien que je ne sais pas si je suis d'accord sur la proportion exacte.
Dans le code que j'écris pour mes clients, c'est plus près de 99%/1%,
quand ce n'est pas carrément 100%/0%, tandis que dans beaucoup de chose
que j'écris pour moi-même, c'est plus près de 50%/50%. (Remarque, vue
qu'environ 80% de ce que j'écris, c'est pour le client, globalement, je
retombe sur son ratio.)

--
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
Marc Boyer
wrote:
Marc Boyer wrote in message
news:<bocv9q$k3m$...

Et Herb Sutter insiste bien sur le fait de ne pas écrire du code
qu'on ne maîtrise pas, et propose un ratio 90%/10% entre ce qu'on
maîtrise et les choses qu'on découvre.


Tu peux m'indiquer une citation ?


Exceptionnal C++, Pb 41, sous-problème 5, dans la VF, c'est p180
(j'aurais préféré la VO, mais comme on avait déjà la VF).

Marc Boyer
--
Lying for having sex or lying for making war? Trust US presidents :-(


1 2