OVH Cloud OVH Cloud

parametres simples en const ?

70 réponses
Avatar
JBB
Bonjour

Lorsque je crée une fonction qui prend un entier en paramètre je fais quelque chose du genre:

int Double( int x)
{
return 2*x;
}

Je me demande s'il il n'est pas plus sage de faire
int Double( const int x)
{
return 2*x;
}
dans la mesure ou je n'ai pas l'intention de modifier x dans le corps.

Cela permettrait d'eviter certaines erreurs (comme affecter x par erreur), par exemple :
int Rapport(const int a,const int b)
{
bool bDivisionParZero = ( b = 0);
if (bDivisionParZero )
{
//exception
}
else
{
return a / b;
}
}
Si b est declare const ce code ne compile pas.
ou alors
int rapport(const int nombreElements,Truc * Tableau)
{
for (;nombreElements >0; nombreElements--)
{
...
}

//renvoyer le nombre d'elements traites
return nombreElements;
}

Est ce une pratique courrante?

10 réponses

Avatar
James Kanze
Sylvain wrote:
Fabien LE LEZ wrote on 04/03/2006 20:38:


Euh... J'ai pas suivi, là. Ne sommes-nous pas sur un forum
consacré au C++ ?



la question posée initialement "une fonction [non membre] qui
prend un entier en paramètre" n'avait donc rien à faire ici ??
que ne nous l'avez vous signifiez plus tôt, un "circulez"
aurait été tout indiqué.


Le forum, c'est fr.comp.lang.c++. On s'intéresse donc aux
solutions C++, et non aux solutions dans d'autres langages.
Quelle aurait été la réaction si j'avais posté qu'il fallait
l'écrire :

(defsub double(x) (* 2 x))

Pas que ça change quelque chose : la situation en C et en C++
est la même : la multiplication s'écrit *, le décalage <<, on
écrit le premier quand on veut multiplier, et le seconde quand
on veut décaler.

Et franchement, si un codeur C++ utilise ce genre de hack,



de quoi ? j'ai pas mon grammar pack sous la main.


Si un codeur C++ ou C utilise ce genre de hack, il se fait virer
de n'importe quelle boîte sérieuse.

La première fois que j'ai vu quelque chose de semblable, c'était
des macros du genre :

#define MUL10(x) ((x) << 3 + (x) << 1)

Dans ce cas précis, l'auteur les avait introduit à cause d'un
problème réel de performance. (L'époque était 1985, environ, et
les compilateurs étaient bien moins intelligents
qu'aujourd'hui.) On a dû les enlever, parce que sur notre
machine (NSC 32000), c'était bien moins rapide que 10 * (x).

Pour le C, je ne sais pas, je ne connais pas ce langage.



il n'est jamais trop tard pour commencer à apprendre.


Non. Toute optimisation est commandée par le profiler,



voui, voui, le code sort du generater, l'IHM du designer, et
l'analyse n'existe simplement plus.


Ce qui veut dire quoi ?

Une chose qui est certaine, c'est que le programmeur ne sait
jamais d'avance où vont se trouver les bouchons. Il y a trop eu
d'études là-dessus pour qu'on prétend le contraire.

une fois qu'on s'aperçoit que le programme réel est
effectivement trop lent.



ah "trop" uniquement, s'il n'est que "assez" lent tout va bien
?


Un programme remplit son cahier de charges, ou il ne le remplit
pas. Il est utilisable, ou il ne l'est pas.

Le fait que le code prend 100 microsecondes de plus au
démarrage, par exemple, ne m'intéresse pas du tout.

--
James Kanze
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
Gabriel Dos Reis
James Kanze writes:

[...]

| En fin de compte, on est professionnel, ou on ne l'est pas.

Woaw.

-- Gaby
Avatar
Sylvain
Beaucoup de bruit pour un post initialement annulé !...

James Kanze wrote on 05/03/2006 12:11:

Le problème actuel, c'est que les opérateurs de << et de >>
signifient surtout l'injection et l'extraction ; c'est leur
utilisation pour le décalage qui représent le surcharge
« abusif ». (Reflechissons un peu, quand même. Quelle est la


après l'argument d'autorité:
"je l'ai jamais vu dans mes sources donc ça n'existe pas"
(remarquez que cela fonctionne aussi en remplaçant "décalage" par
"intelligence")

l'argument moral, ce serait "abusif", ah bon; on passe son temps à
répéter que le compilo va générer cette instruction (SHL) mais il est
abusif de l'utiliser soi-même; votre logique m'échappe.

(Reflechissons un peu, quand même. Quelle est la
signification que le programmeur voir d'abord ? Quelle est
l'utilisation la plus fréquente ?)


disons que si il lit:

cout << "titi" << anInt << "toto";

il a le droit de comprendre que c'est de l'injection dans un stream.

et si il lit:

t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ...;
t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ...;
t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ...;
t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ...;

il a le droit de comprendre que ce sont des décalages de bits.

vous parlez à chaque fois de "lire", jamais de "comprendre", c'est pour
être dans l'air du temps j'imagine (cette distinction n'étant pas propre
à l'informatique).

Pas moins lisible. Il dit quelque chose de différent. On utilise
un quand on veut décaler les bits, et l'autre quand on veut
multiplier une valeur par deux.


soutenir que décaler de 1 bit "dit" quelque chose de différent de
multiplier (ou diviser) par 2 frise le non-sens ... ou l'acharnement
dogmatique: dans l'exemple ci-dessus s0, s1, etc sont des longs et non
des instances de std::bitset, autoriserez-vous malgré tout l'emploi de
">>" ?

Apparamment, tu ne sais pas lire le C++, parce qu'il s'agit ici
de multiplier par 2, et en C++, l'opérateur de multiplication
est *, et la constante deux s'écrit 2. Toute autre forme
d'écriture est de l'obfuscation, pûre et simple -- une signe
d'incompétence professionnelle.


je le lis assez bien pour comprendre sans ambiguïté un opérateur dans
son contexte.

une prétendue obfuscation _au niveau code source_ ne peut être a
contrario qu'une faible excuse pour quelqu'un qui en effet ne saurait
pas ou aurait qlq difficulté à lire du C++.

ce second dogme m'apparait également assez amusant: le développeur
"professionnellement compétent" ou simplement à la mode écrit du "code
lisible" (sans il soit nécessaire de définir, normer cette lisibilité
d'ailleurs).

je ne sais pas si c'est ici le fruit d'une nouvelle pédagogie bien
récitée et apprise par coeur: on ne commente plus ses sources, on
tronçonne toute méthode de plus de 20 lignes, on utilise les librairies
standards et surtout aucune expression condensée.
à moins que ce soit une tendance néo-open sourcesque: "mon code est
lisible parce que la Terre-entière le relit".

je croyais la pertinence ailleurs: qu'un header, un idl ou généralement
une interface soit "lisible", claire et détaillée me parait plus
qu'indispensable; mais l'implémentation de la petite méthode machin
perdue au fond d'une librairie, elle fonctionne ou non, point barre.
(ça ne justifie pas qu'elle soit codée de manière la plus illisible
possible,) mais clairement j'aurais besoin de la relire que si elle est
buggée et doit être recodée - je sais que vous allez répondre: "et
comment tu fixes l'erreur si c'est pas bien "lisible" ?", je préfère
juste une méthode non buggée dès le départ, pas un truc que je /peux/
relire parce que je /dois/ débugger.

Et là, je ne peut que dire que c'est un mensonge, ou que tu ne
sais pas mesurer, parce que j'ai fait des mesures avec le
compilateur Sun CC, sur Sparc. C'est un compilateur que je
connais bien.


merci pour le menteur que je ne commenterais pas.

je n'ai pratiqué ces compilo (dont GNU C++ release 2.0 d'avril 1992) sur
Sun que pendant 6 ans, je pense les connaître également.

En fait, la technologie pour le faire est bien connu, et ça,
depuis longtemps.


quelqu'un a dit le contraire ???

TC 2.0 de Borland le faisait dès 1990, les compilos M$ ne l'ont jamais fait.

Si un compilateur n'effectue pas l'optimisation
aujourd'hui, c'est temps de changer de compilateur.


ah ben ouais, yaka, j'suis con !

Et même, l'obfuscation n'est permis que dans le cas où rien
d'autre ne marche.


ça sent encore la mauvaise foi: l'obfuscation (au niveau code source) ne
traduisant que l'incapacité d'un relecteur à comprendre un code,
celle-ci sera autorisée uniquement si ce dernier est incapable de
concevoir un autre codage pour la même opération; dont acte!

et comment code-t-il (x * 80) ? ((x << 4) + (x << 6))
A priori. Je ne l'ai pas regardé.



perds pas de temps à regarder, seul Borland le fait (ni M$, ni GCC, ni
Sun CC - je n'ai pas testé le compilo Intel).

Je questionnerai bien la compétence d'un programmeur qui écrit
un décalage quand il veut multiplier, et vice versa.


plonge toi dans une librairie mathématique (cryptlib, crypto++,
trueCrypt, etc) et va questionner leurs programmeurs.

Un programme, c'est fait avant tout pour être lu par des hommes.


ah bon ?!?!?? je pensais bêtement que c'était fait *avant tout* pour
être exécuter par un proc ...

En fin de compte, on est professionnel, ou on ne l'est pas.


professionnel de lecture de code au coin du feu ??
pardonnez la boutade mais ces propos hautains sont carrément ridicules.

Sylvain.


Avatar
Cyrille

et comment code-t-il (x * 80) ? ((x << 4) + (x << 6))
A priori. Je ne l'ai pas regardé.



perds pas de temps à regarder, seul Borland le fait (ni M$, ni GCC, ni
Sun CC - je n'ai pas testé le compilo Intel).


Soit j'ai pas compris, soit vous faites erreur, pour Microsoft sur
architecture Pentium au moins.
Testé sur Microsoft Visual C++ 2005: si le compilateur ne transforme pas
x*80 en ((x << 4) + (x << 6)), c'est parce que le compilateur a mieux:
0040101D lea esi,[eax+eax*4]
00401020 shl esi,4

Si je remplace x*80 par un calcul avec des shifts, il me produit la même
chose. Donc le compilateur de Microsoft optimise aussi à sa sauce. Bien
sûr ce n'est pas le cas si je désactive les optimisations.

(pour savoir pourquoi lea plutôt que shl: "LEA is better than SHL on the
Pentium because it pairs
in both pipes, SHL pairs only in the U pipe."
http://www.goof.com/pcg/doc/pentium-optxref.html)

De même, il génère le même binaire si on lui sert un x*127 ou un x<<7 -
x. (il utilise un imul).

Je questionnerai bien la compétence d'un programmeur qui écrit
un décalage quand il veut multiplier, et vice versa.


plonge toi dans une librairie mathématique (cryptlib, crypto++,
trueCrypt, etc) et va questionner leurs programmeurs.


Je viens de télécharger cryptlib juste pour voir, du coup, et je n'y
vois pas de << qu'on puisse attribuer à une volonté de faire une
multiplication. C'est quasiment à chaque fois soit un travail sur les
bits (endianness, encodage de données dans un entier), souvent associé
avec des & ou des | soit le calcul d'une puissance entière de 2.
Par contre on voit des * 2, des * 3, des * 4... les auteurs ont
visiblement compté sur l'optimisation du compilateur.

Bien sûr c'est un survol rapide que j'ai fait.

Un programme, c'est fait avant tout pour être lu par des hommes.


ah bon ?!?!?? je pensais bêtement que c'était fait *avant tout* pour
être exécuter par un proc ...


Bon, faut arrêter de dire n'importe quoi, là. Il est évident que le code
est destiné à être lu par une machine, mais il est aussi évident qu'il
est fait par et pour des êtres humains et qu'il doit rester au maximum
compréhensible par ceux-ci. Et quand on dit compréhensible, c'est
compréhensible immédiatement si possible.

Pour une machine x*80 ou ((x << 4) + (x << 6)), c'est du pareil au même.
Par contre pour un humain, non. Enfin si, au plan formel, en y pensant
quelques secondes, on peut voir que les deux formes sont équivalentes.
Mais à la lecture, quand on lit ((x << 4) + (x << 6)), on est obligé de
se poser la question "quelle était l'intention du programmeur"?
Travailler sur l'enchaînement des bits ou faire un calcul? Bien sûr on
peut s'en tirer avec un seyant commentaire à côté, mais j'ai quand même
une vague impression de perte de temps dans l'affaire.

--
"Kill Them All!" ~ Mohandas Karamchand "Mahatma" Gandhi



Avatar
Fabien LE LEZ
On Sun, 05 Mar 2006 12:11:14 +0100, James Kanze :

En fait, la technologie pour le faire est bien connu, et ça,
depuis longtemps. Si un compilateur n'effectue pas
l'optimisation aujourd'hui, c'est temps de changer de
compilateur.


Ou peut-être, tout simplement, qu'utiliser des décalages n'est *pas*
une optimisation sur un processeur donné.

Au finale, le compilo a un avantage sur le programmeur : il sait quel
est le processeur cible, et connait parfaitement ses caractéristiques.

Avatar
Sylvain
Cyrille wrote on 05/03/2006 17:38:

et comment code-t-il (x * 80) ? ((x << 4) + (x << 6))
A priori. Je ne l'ai pas regardé.



perds pas de temps à regarder, seul Borland le fait (ni M$, ni GCC, ni
Sun CC - je n'ai pas testé le compilo Intel).


Soit j'ai pas compris, soit vous faites erreur, pour Microsoft sur
architecture Pentium au moins.
Testé sur Microsoft Visual C++ 2005: si le compilateur ne transforme pas
x*80 en ((x << 4) + (x << 6)), c'est parce que le compilateur a mieux:
0040101D lea esi,[eax+eax*4]
00401020 shl esi,4


vous avez compris le point mais le contexte était moins évident.

je n'ai qu'indiqué que "2 * x" pouvait s'écrire "x << 1", de là vient ce
thread pour sermonner qu'il "est mal" de faire un shift, que les
optimiseurs ceci ou que Pentium cela.

les arguments préhistoriques (tel le 8086 ou GCC 2.0 de 1992) ne servant
qu'à noyer le non fondement de l'argument "il est mal de".

pour votre exemple, le codage montré ici tient en fait à l'architecture
des Pentium, un chargement (load effective) d'une expression calculée
est IMHO impossible sur un 86, 286; par ailleurs si ces optim. sont
enfin supportées par VC2005, ce n'était pas le cas de cl 12.00 (VC98)
qui génère:
mov eax, dword @x
imul eax,eax,50h
mov dword @x,eax

plonge toi dans une librairie mathématique (cryptlib, crypto++,
trueCrypt, etc) et va questionner leurs programmeurs.


Je viens de télécharger cryptlib juste pour voir, du coup, et je n'y
vois pas de << qu'on puisse attribuer à une volonté de faire une
multiplication. [...]


hmmm, faire une multiplication ou une division entière par une puissance
de 2 *est* faire un décalage.

si parcourir tout cryptLib est fastidieux, code (sur un proc 32bits)
avec uniquement l'opérateur "*" la bête opération

Z y = x * 2^43;

où x et y sont de même type Z (type primitif ou instance d'une classe
que tu définiras librement).

Un programme, c'est fait avant tout pour être lu par des hommes.


ah bon ?!?!?? je pensais bêtement que c'était fait *avant tout* pour
être exécuter par un proc ...


Bon, faut arrêter de dire n'importe quoi, là. Il est évident que le code
est destiné à être lu par une machine, mais il est aussi évident qu'il
est fait par et pour des êtres humains et qu'il doit rester au maximum
compréhensible par ceux-ci. Et quand on dit compréhensible, c'est
compréhensible immédiatement si possible.


tout à fait d'accord, mais "fait par des êtres humains" ne signifie pas
"tellement dépourvu de toute astuce de codage qu'il soit compréhensible
par *tout* être humain" (ce n'est pas un point d'élitisme, juste une
évidence professionnelle); et "fait pour des êtres humains" n'a jamais
obligé un utilisateur humain à lire dans le texte le source de l'appli
qu'il utilise.

Pour une machine x*80 ou ((x << 4) + (x << 6)), c'est du pareil au même.
[...]


je n'ai pas encouragé une telle écriture; j'ai dit qu'il était creux de
glousser des "c'est mal".

Sylvain.




Avatar
Gabriel Dos Reis
Fabien LE LEZ writes:

[...]

| Au finale, le compilo a un avantage sur le programmeur : il sait quel
| est le processeur cible, et connait parfaitement ses caractéristiques.

« Parfaitement » je ne sais pas.

-- Gaby
Avatar
Loïc Joly
On Sun, 05 Mar 2006 12:11:14 +0100, James Kanze :


En fait, la technologie pour le faire est bien connu, et ça,
depuis longtemps. Si un compilateur n'effectue pas
l'optimisation aujourd'hui, c'est temps de changer de
compilateur.



Ou peut-être, tout simplement, qu'utiliser des décalages n'est *pas*
une optimisation sur un processeur donné.

Au finale, le compilo a un avantage sur le programmeur : il sait quel
est le processeur cible, et connait parfaitement ses caractéristiques.


C'est un avantage souvent avancé (un autre étant le profiling en cours
d'appli) par les partisans de la compilation JIT.

--
Loïc


Avatar
Marc Boyer
Le 04-03-2006, Sylvain a écrit :
Alexandre wrote on 04/03/2006 16:52:
acte 2: "x << 1" serait /moins lisible/ que "2 * x"

ce bavardage (ou avis très personnel) m'amuse un peu, si un codeur C ne
sait pas lire "x << n" je lui conseillerais humblement de commencer à
s'initier au langage qu'il pense utiliser ou de passer à autre chose.


Et s'il faisait du C++ justement ?

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exiter des sots
IF -- Rudyard Kipling (Trad. Paul Éluard)

Avatar
kanze
Loïc Joly wrote:
On Sun, 05 Mar 2006 12:11:14 +0100, James Kanze
:

En fait, la technologie pour le faire est bien connu, et ça,
depuis longtemps. Si un compilateur n'effectue pas
l'optimisation aujourd'hui, c'est temps de changer de
compilateur.


Ou peut-être, tout simplement, qu'utiliser des décalages
n'est *pas* une optimisation sur un processeur donné.

Au finale, le compilo a un avantage sur le programmeur : il
sait quel est le processeur cible, et connait parfaitement
ses caractéristiques.


C'est un avantage souvent avancé (un autre étant le profiling
en cours d'appli) par les partisans de la compilation JIT.


C'est un avantage réel. Différents processeurs de la même
famille ont des caractèristiques différents.

Si le programme ne doit tourner que sur un seul processeur, le
compilateur Sun CC, au moins, a des options pour dire de
l'optimiser pour ce processeur précis. Dans la pratique,
évidemment, on le fait peu, parce que c'est possible que le
binaire qui en résulte ne tourne même pas sur un autre
processeur. Tandis qu'avec un JIT, chaque binaire ne tourne que
sur un seul processeur, par définition.

--
James Kanze GABI Software
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