OVH Cloud OVH Cloud

Decalages d'un nombre de bits pouvant etre >= a la taille du type

134 réponses
Avatar
Vincent Lefevre
J'ai besoin de faire un décalage vers la droite sur un type entier
(disons non signé) générique (i.e. défini par typedef) d'un certain
nombre constant de bits. Le problème est que ce nombre de bits peut
être supérieur ou égal à la taille du type en question. Une idée
sur la façon de faire ça efficacement sans obtenir de comportement
indéfini et sans passer par un outil du style "configure"?

--
Vincent Lefèvre <vincent@vinc17.org> - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

10 réponses

Avatar
Vincent Lefevre
Dans l'article <4166b2ff$0$15753$,
Richard Delorme écrit:


On peut donc utiliser <limits.h> et le preprocesseur:

#include <limits.h>

#if (INT_MAX >> 15) == 1
// on est en 16 bits
#elif (INT_MAX >> 31) == 1
// ici les int font 32 bits
#elif (INT_MAX >> 63) == 1
// super des gros int de 64 bits
#else
// toto, mais ou sommes nous ? plus au Kansas en tout cas.
#endif


Ça ne marche pas, ça trouve toujours des int de 16 bits.


(INT_MAX >> 15) == 1 est toujours vrai??? Il y a une raison?

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA


Avatar
Vincent Lefevre
Dans l'article <ck6d3g$nso$,
Antoine Leca écrit:

Mais si on me trouve un moyen d'éviter la cascade de #elif, ce
serait plus joli...


Surtout que mon code est déjà dans un #define, et des #if ... dans
un #define, ça ne me semble pas possible. Et faire un #define dans
chaque #if, c'est trop lourd pour la maintenance du code (tant que
je le maintiens).

Depuis C99, les seules représentations possibles pour les entiers sont
binaires (6.2.6.2); avec C90 c'est vrai que tu pouvais avoir d'autres
représentations, mais la pratique n'en a pas montré beaucoup...


Ils ont gardé les représentation en complément à 1 et en signe + valeur
absolue. Il y a une raison? Est-ce que c'est utilisé quelque part?

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Vincent Lefevre
Dans l'article ,
Gabriel Dos Reis écrit:

Vincent Lefevre <vincent+ writes:

| Dans l'article ,
| Gabriel Dos Reis écrit:
|
| > Vincent Lefevre <vincent+ writes:
|
| > | Dans l'article <cjvbua$f0p$,
| > | Charlie Gordon écrit:
|
| > | > 1 ? 0 : 1>>32
| > |
| > | L'implémentation peut ne pas évaluer 1>>32. Mais elle peut aussi
| > | l'évaluer en tant que sous-expression constante (sans chercher à
| > | savoir si la valeur pourra être utilisée ou si elle ne sera jamais
| > | utilisée), et dans ce cas, il y a comportement indéfini.
|
| > Bah non ; ce n'est pas un comportement possible de la machine
| > abstraite.
|
| Sur quoi tu te bases?

Le machin que tu cites à tout le monde.


Ça ne dit pas que ce n'est pas un comportement possible de la machine
abstraite.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Richard Delorme
Dans l'article <4166b2ff$0$15753$,
Richard Delorme écrit:




On peut donc utiliser <limits.h> et le preprocesseur:

#include <limits.h>

#if (INT_MAX >> 15) == 1
// on est en 16 bits
#elif (INT_MAX >> 31) == 1
// ici les int font 32 bits
#elif (INT_MAX >> 63) == 1
// super des gros int de 64 bits
#else
// toto, mais ou sommes nous ? plus au Kansas en tout cas.
#endif




Ça ne marche pas, ça trouve toujours des int de 16 bits.



(INT_MAX >> 15) == 1 est toujours vrai??? Il y a une raison?


Euh non, j'ai dit une bêtise, mais le code ne marchait pas quand même.

--
Richard



Avatar
Vincent Lefevre
Dans l'article <41656e1c$0$15754$,
Richard Delorme écrit:

Et que dit le verset 11 du 6.6 ?


Ah, seule la note du 11 (mais non normative?) précise, et encore,
leur exemple est assez mauvais (ceci dit, les miens n'étaient pas
forcément bons non plus).

Par exemple, si on considère k || 1 / 0 (j'ai pris volontairement
quelque chose qui n'était pas constant devant le ||), la seule
expression constante est 1 / 0. Le verset 11 dit:

[#11] The semantic rules for the evaluation of a constant
expression are the same as for nonconstant expressions.88)

La règle sémantique de l'évaluation de 1 / 0 est comme celle d'une
expression non constante, donc ici, comportement indéfini. Mais
comme l'évaluation se fait à la traduction, le comportement indéfini
se produit au niveau de la traduction. À partir de là, plus rien
n'est garanti et le code généré peut faire n'importe quoi dès le
début de l'exécution du programme généré (même si k serait toujours
non nul).

Maintenant, la note 88 semble dire qu'un comportement indéfini
dans une évaluation lors de la traduction n'a aucune influence sur
l'exécution. Mais cela n'est pas une conséquence du verset 11.

Si le verset 11 avait été écrit comme ceci: "The semantic rules for
a constant expression are the same as for nonconstant expressions",
la note 88 aurait bien été une conséquence du verset 11, car ici,
on s'intéresse à l'expression elle-même et non pas à son évaluation
à la traduction (lorsque celle-ci est évaluée à la traduction).

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Vincent Lefevre
Dans l'article <ck3une$2to$,
Antoine Leca écrit:

En 20041007161056$,
Vincent Lefevre va escriure:
Autrement dit, dans l'expression ternaire, exactement deux
sous-expressions sont _évaluées_, l'autre ne l'est pas.


Ça, c'est le cas général à l'exécution.


Euh ?
Où ai-je écrit « exécution » ?


C'est moi qui le dit (le compilo peut très bien évaluer une expression
constante à l'exécution).

Mais la norme dit que les expressions constantes peuvent être
évaluées à la traduction (6.6),


Et alors ? À la traduction, on va évaluer la première
sous-expression, et si elle est constante (cela vaux mieux) on va
ensuite choisir « d'évaluer » (au sens de la machine virtuelle)
l'une ou l'autre des deux autres sous-expressions. Où est le
problème ?


Le problème est que tu supposes ici que toutes les expressions
constantes sont évaluées à la traduction. Dans 2 || 1 / 0, le
compilateur peut très bien choisir d'évaluer le || à l'exécution,
et de ne considérer que l'expression constante 1 / 0 à évaluer à
la traduction (c'est stupide, mais bon, c'est autorisé par la
norme, non?). Ensuite, cf ma réponse à Richard.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA



Avatar
Laurent Deniau
Antoine Leca wrote:
En ck698e$ssu$, Charlie Gordon va escriure:
Mais il est vrai que rien n'oblige à ce que l'arithmétique se fasse
en base 2.



Depuis C99, les seules représentations possibles pour les entiers sont
binaires (6.2.6.2); avec C90 c'est vrai que tu pouvais avoir d'autres
représentations, mais la pratique n'en a pas montré beaucoup...


les ordinateurs quantiques ne se programmeront pas en C ;-)

a+, ld.


Avatar
Vincent Lefevre
Dans l'article ,
Horst Kraemer écrit:

Non. Le comportement de

1 ? 0 : 1>>32

est défini de par la norme. Le fait qu'une expression constante
pourrait être évaluée "physiquement" pendant la traduction ne touche
pas le fait qu'elle n'est évaluée dans la machine abstraite si et
seulement si la norme dit qu'elle sera évaluée.


Sauf que ce n'est pas du tout dit par la norme.

D'ailleurs la norme donne comme exemple d'une expression définie:

static int i = 2 || 1/0;


Le problème est que cet exemple ne correspond pas à ce que dit la
norme (cf ma réponse à Richard -- c'est très probablement une erreur
dans le texte de la norme).

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Antoine Leca
En 20041008162131$, Vincent Lefevre va escriure:
Par exemple, si on considère k || 1 / 0 (j'ai pris volontairement
quelque chose qui n'était pas constant devant le ||),


Soit k est constant (évaluable pendant la traduction), et alors le fait de
cacher une constante derrière un identificateur ne fait que compliquer la
discussion.

Soit il n'est pas constant, et on est hors du cadre.

Le verset 11 dit:

[#11] The semantic rules for the evaluation of a constant
expression are the same as for nonconstant expressions.88)

La règle sémantique de l'évaluation de 1 / 0 est comme celle d'une
expression non constante, donc ici, comportement indéfini.


Encore une fois, si k ne s'évalue pas comme 0, non. L'expression est évaluée
comme valant 1. Le comportement externe est parfaitement défini.

Et pour que l'expression puisse être une expression constante, k doit être
constant; c'est donc parfaitement décidable pour le compilateur.

Tu te mords la queue dans ton explication: tu dis que les expressions non
constantes n'ont pas de problèmes, seules les expressions constantes posent
problème; hors tu concèdes que les expressions constantes s'évaluent selon
les règles des expressions non constantes (qui ne posent pas de problème);
pourtant tu vois un problème...


Antoine

Avatar
Vincent Lefevre
Dans l'article <ck5flc$m4s$,
Charlie Gordon écrit:

Enfin sur une plateforme 64 bits avec des int de 64 bits, 1 >> 32 ne doit
déclencher un warning que si l'on recherche la portabilité.
Imagine la quantité de warning que déclencherait n'importe quel bout de code
non trivial si le compilo mettait systematiquement en garde sur les
problèmes de portabilité 16 bits...


C'est pour cela que je dis que ça devrait être configurable.

Quels sont les outils qui détectent les constructions non portables, en
fonction d'un ensemble de cibles spécifié : 16, 32, 64, LE, BE, int!=long,
pointeurs!=int, pointeurs data!=pointeurs code, float/double,
size_t!=unsigned int, et des tas d'autres ?


Note que stocker un long dans un int n'est pas forcément une erreur,
et ceci quelle que soit l'implémentation (par exemple, si la valeur
en question est 0, c'est toujours OK). Ce n'est pas le cas de >> 32
sur un int, où avec certaines implémentations, c'est systématiquement
une erreur. Pour cette raison, un warning peut être justifié.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA