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
Horst Kraemer
Vincent Lefevre <vincent+ wrote:

Dans l'article <cjvbua$f0p$,
Charlie Gordon écrit:

Après relecture du standard, il apparait que 1>>32 c'est undefined behavior,
y compris pendant la translation.
Je pense quand même que 1 ? 0 : 1>>32 est sémantiquement correct,
d'ailleurs 6.6 paragraphe 3 prévoit le cas d'expressions constantes dont des
sous-expressions non constantes ne sont jamais évaluées. Par exemple :

3 * sizeof(main(argc,argv))
1 ? 0 : main(argc,argv)

alors pourquoi pas

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.


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.

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

static int i = 2 || 1/0;


--
Horst

--
Lâche pas la patate!


Avatar
Gabriel Dos Reis
Laurent Deniau writes:

| Vincent Lefevre wrote:
| > Dans l'article <ck3g2f$1im$,
| > Laurent Deniau écrit:
| >
| >> Le cast n'est pas un probleme selon tes propos (c'etait ma premiere
| >> question) et il est biensur essentiel pour fixer le type de index_t.
| > Le cast en lui-même n'était pas un problème dans ton exemple
| > (qui n'utilisait pas le préprocesseur), mais qui ne résolvait
| > pas non plus le problème.
| >
| >>Le choix du unsigned long n'est pas anodin. Il correspond
| >>generalement au plus gros mot processeur (32, 64, 128, ...)
| > Non, c'est complètement faux! Sur une machine 32 bits, un
| > unsigned long fait 32 bits, alors qu'un unsigned long long
| > en fait 64.
|
| Je parle chinois? relis ce que j'ai ecrit stp...

bah, tu parles pas Éwé en tout cas :-)

-- Gaby
Avatar
Gabriel Dos Reis
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.

-- Gaby
Avatar
Gabriel Dos Reis
Vincent Lefevre <vincent+ writes:

| Dans l'article <ck3i0s$2r0$,
| Antoine Leca écrit:
|
| > En 20041007115911$, Vincent Lefevre va escriure:
| > > Dans l'article <ck0fuf$q8h$,
| > > Antoine Leca écrit:
| > >
| > >> Autrement dit, si le comportement indéfini est dans du code non
| > >> évalué, [...]
| > >
| > > Mais si le comportement indéfini est dans du code évalué à la
| > > traduction (cf 6.6#2, ce qui est le cas qui me préoccupe)?
|
| > Est-il évalué, ou non ?
|
| Il est très probablement évalué à la traduction

Pourquoi faire ?

| (c'est une optimisation).

Une optimisation ne change pas le fonctionnement observable.

-- Gaby
Avatar
Gabriel Dos Reis
Vincent Lefevre <vincent+ writes:

| Dans l'article <ck3m5s$p4c$,
| Antoine Leca écrit:
|
| > Je parlais d'évaluation au sens de la norme.
| > 6.5.15p4: "The first operand is evaluated; there is a sequence point
| > after its evaluation. The second operand is evaluated *only* if
| > [...]" (c'est moi qui souligne).
|
| > 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.

Oui et c'est ce qui compte.

Si tu as un compilateur qui fait autre chose, rapporte-le à celui qui
t'a berné.

-- Gaby
Avatar
Gabriel Dos Reis
Vincent Lefevre <vincent+ writes:

| Dans l'article <cjvb19$d09$,
| Charlie Gordon écrit:
|
| > "Vincent Lefevre" <vincent+ wrote in message
| > news:20041005221856$
|
| > > Il l'est. Le test n'a aucun influence ici. Le compilo peut très
| > > bien évaluer des expressions au moment de la traduction (cas des
| > > expressions constantes). Comme pour chaque valeur du terme de
| > > gauche il y a comportement indéfini, l'implémentation peut faire
| > > ce qu'elle veut, à savoir, considérer que la valeur est constante.
| > > Dans ce cas, toutes les contraintes du 6.6 sont satisfaites.
|
| > Pas du tout ! C'est le code produit qui a un comportement indéfini,
| > pas le compilateur.
|
| Je n'ai pas dit que le compilateur avait un comportement indéfini,
| mais qu'elle avait le droit de faire ce qu'elle veut concernant la
| traduction du code en question.

c'est du n'importe quoi.

-- Gaby
Avatar
Gabriel Dos Reis
Vincent Lefevre <vincent+ writes:

| Dans l'article ,
| Jean-Marc Bourguet écrit:
|
| > Pourquoi? En supposant l'absence de bit de padding le decalage n'est
| > pas evalue dans sauf si le compilateur peut montrer qu'il n'a pas
| > d'effet. Meme si ce n'etait pas le cas, le compilateur qui genere du
| > comportement indefini mechant pour ca dans le cas ou (c) est une
| > constante est de toute maniere bon a jeter.
|
| Le problème est l'évaluation (au moment de la traduction) d'une
| constante dont le résultat est indéfini.

Mais c'est n'importe quoi.

-- Gaby
Avatar
Charlie Gordon
"Vincent Lefevre" <vincent+ wrote in message
news:20041007120136$
Je n'ai pas dit cela. Attention, je ne me fixe pas sur une
implémentation particulière. Par exemple, si quelqu'un écrit

int main(void)
{
return 1 >> 32;
}

avec certaines (de nombreuses) implémentations, ça va toujours
fonctionner, mais ce n'est pas du tout portable. Un warning me
semble donc justifié ...


Un warning pour le code en question est justifié sur les plateformes 32
bits, d'ailleurs ce pourrait etre une erreur.
Par contre le code suivant n'a aucune raison de déclencher un warning :

1 ? 1 : 1 >> 32;

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...

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 ?

Chqrlie.

Avatar
Charlie Gordon
"Vincent Lefevre" <vincent+ wrote in message
news:20041004141107$
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"?


Une nouvelle piste à explorer pour ce thread déjà bien fourni :

Pourrait-on utiliser le préprocesseur de cette facon (en excluant le cas de
la cross-compilation) ?

#if (2 << 15) == 0
// ici en est sur une plateforme 16 bits, definir la macro qui va bien
#elif (2 << 31) == 0
// ici les entiers sont sur 32 bits : autre version
#else
//... etc
#endif

Je peux imaginer des tonnes d'arguments pour interdire une telle approche,
mais restreignons nous à la norme.

Chqrlie.

Avatar
Laurent Deniau
Charlie Gordon wrote:
"Vincent Lefevre" <vincent+ wrote in message
news:20041004141107$

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"?



Une nouvelle piste à explorer pour ce thread déjà bien fourni :

Pourrait-on utiliser le préprocesseur de cette facon (en excluant le cas de
la cross-compilation) ?

#if (2 << 15) == 0
// ici en est sur une plateforme 16 bits, definir la macro qui va bien
#elif (2 << 31) == 0
// ici les entiers sont sur 32 bits : autre version
#else
//... etc
#endif

Je peux imaginer des tonnes d'arguments pour interdire une telle approche,
mais restreignons nous à la norme.


non (6.10.1-3) parce que le preprocesseur travaille sur intmax_t (ou
uintmax_t) qui peuvent etre plus grand que int ou long puisque c'est le
plus grand type intregral supporte par le compilateur. Donc ce que tu
testes, c'est la taille de intmax_t pas celle de int ou long. Cela pose
aussi le probleme de la cross-compilation.

a+, ld.