La macro évidente :
#define SAFE_RSHIFT(v, c) ((sizeof(v)*CHAR_BIT >= (c)) ? 0 : (v) >> (c))
a plusieurs inconvénients :
- la comparaison est faite à l'envers, ce qui est facile à corriger ;-)
- c est instancié deux fois.
- on a potentiellement un comportement indéfini sur une partie de
l'expression.
- on a un warning stupide dans ce cas si c est constant et que le
compilateur se croit malin.
- on peut aussi avoir un warning si c est une expression d'un type signé à
cause de la comparaison signé/non-signé
- le code généré est inefficace si c est une expression non constante (2
jump)
On peut remédier à ces inconvénients comme ceci:
- on utilise une fonction inline au lieu d'une macro, mais cela force le
type de v, ce qui n'est pas forcement loisible
- on peut masquer c dans le shift, ce qui supprime le warning sans
changer le code pour les valeurs constantes de c, mais ralentit un
peu les instances ou c est non constante, à moins que le compilo
soit très fort et que l'architecture s'y prete. On peut aussi
utiliser 2 macros differentes pour les shifts constants et calculés.
- on caste (c) en (unsigned)
- on peut faire une expression sans test, ce qui generera un
meilleur code si le compilo est subtil.
Ceci suppose que le shift signé duplique le bit de signe. Donc à
n'utiliser que sur les architectures où cette supposition est valide
PS: je trouve regrettable que le shift d'une quantité *constante*
supérieure à la taille du type non soit pas défini avec la
sémantique évidente, mais je suppose que c'est pour préserver la
cohérence et l'efficacité de l'implémentation.
La macro évidente :
#define SAFE_RSHIFT(v, c) ((sizeof(v)*CHAR_BIT >= (c)) ? 0 : (v) >> (c))
a plusieurs inconvénients :
- la comparaison est faite à l'envers, ce qui est facile à corriger ;-)
- c est instancié deux fois.
- on a potentiellement un comportement indéfini sur une partie de
l'expression.
- on a un warning stupide dans ce cas si c est constant et que le
compilateur se croit malin.
- on peut aussi avoir un warning si c est une expression d'un type signé à
cause de la comparaison signé/non-signé
- le code généré est inefficace si c est une expression non constante (2
jump)
On peut remédier à ces inconvénients comme ceci:
- on utilise une fonction inline au lieu d'une macro, mais cela force le
type de v, ce qui n'est pas forcement loisible
- on peut masquer c dans le shift, ce qui supprime le warning sans
changer le code pour les valeurs constantes de c, mais ralentit un
peu les instances ou c est non constante, à moins que le compilo
soit très fort et que l'architecture s'y prete. On peut aussi
utiliser 2 macros differentes pour les shifts constants et calculés.
- on caste (c) en (unsigned)
- on peut faire une expression sans test, ce qui generera un
meilleur code si le compilo est subtil.
Ceci suppose que le shift signé duplique le bit de signe. Donc à
n'utiliser que sur les architectures où cette supposition est valide
PS: je trouve regrettable que le shift d'une quantité *constante*
supérieure à la taille du type non soit pas défini avec la
sémantique évidente, mais je suppose que c'est pour préserver la
cohérence et l'efficacité de l'implémentation.
La macro évidente :
#define SAFE_RSHIFT(v, c) ((sizeof(v)*CHAR_BIT >= (c)) ? 0 : (v) >> (c))
a plusieurs inconvénients :
- la comparaison est faite à l'envers, ce qui est facile à corriger ;-)
- c est instancié deux fois.
- on a potentiellement un comportement indéfini sur une partie de
l'expression.
- on a un warning stupide dans ce cas si c est constant et que le
compilateur se croit malin.
- on peut aussi avoir un warning si c est une expression d'un type signé à
cause de la comparaison signé/non-signé
- le code généré est inefficace si c est une expression non constante (2
jump)
On peut remédier à ces inconvénients comme ceci:
- on utilise une fonction inline au lieu d'une macro, mais cela force le
type de v, ce qui n'est pas forcement loisible
- on peut masquer c dans le shift, ce qui supprime le warning sans
changer le code pour les valeurs constantes de c, mais ralentit un
peu les instances ou c est non constante, à moins que le compilo
soit très fort et que l'architecture s'y prete. On peut aussi
utiliser 2 macros differentes pour les shifts constants et calculés.
- on caste (c) en (unsigned)
- on peut faire une expression sans test, ce qui generera un
meilleur code si le compilo est subtil.
Ceci suppose que le shift signé duplique le bit de signe. Donc à
n'utiliser que sur les architectures où cette supposition est valide
PS: je trouve regrettable que le shift d'une quantité *constante*
supérieure à la taille du type non soit pas défini avec la
sémantique évidente, mais je suppose que c'est pour préserver la
cohérence et l'efficacité de l'implémentation.
Dans l'article <cjucbf$lub$,
Laurent Deniau écrit:Defini dans tous les cas mais ne fait pas necessairement ce que tu veux
en >32 bits d'ou ma suggestion initiale de passer par le preprocesseur
pour selectionner le code correct. Idem pour le warning du compilo.
Non, la norme dit bien que c'est du comportement indéfini.
6.5.7 Bitwise shift operators
[...]
[#3] The integer promotions are performed on each of the
operands. The type of the result is that of the promoted
left operand. If the value of the right operand is negative
or is greater than or equal to the width of the promoted
left operand, the behavior is undefined.
Dans l'article <cjucbf$lub$1@sunnews.cern.ch>,
Laurent Deniau <Laurent.Deniau@cern.ch> écrit:
Defini dans tous les cas mais ne fait pas necessairement ce que tu veux
en >32 bits d'ou ma suggestion initiale de passer par le preprocesseur
pour selectionner le code correct. Idem pour le warning du compilo.
Non, la norme dit bien que c'est du comportement indéfini.
6.5.7 Bitwise shift operators
[...]
[#3] The integer promotions are performed on each of the
operands. The type of the result is that of the promoted
left operand. If the value of the right operand is negative
or is greater than or equal to the width of the promoted
left operand, the behavior is undefined.
Dans l'article <cjucbf$lub$,
Laurent Deniau écrit:Defini dans tous les cas mais ne fait pas necessairement ce que tu veux
en >32 bits d'ou ma suggestion initiale de passer par le preprocesseur
pour selectionner le code correct. Idem pour le warning du compilo.
Non, la norme dit bien que c'est du comportement indéfini.
6.5.7 Bitwise shift operators
[...]
[#3] The integer promotions are performed on each of the
operands. The type of the result is that of the promoted
left operand. If the value of the right operand is negative
or is greater than or equal to the width of the promoted
left operand, the behavior is undefined.
Dans l'article <cjusr0$k5$,
Charlie Gordon écrit:La macro évidente :
#define SAFE_RSHIFT(v, c) ((sizeof(v)*CHAR_BIT >= (c)) ? 0 : (v) >>
(c))
- la comparaison est faite à l'envers, ce qui est facile à corriger ;-)
- on a potentiellement un comportement indéfini sur une partie de
l'expression.
- on a un warning stupide dans ce cas si c est constant et que le
compilateur se croit malin.
Ce n'est pas un warning stupide puisqu'il est justifié: comportement
indéfini (même si en pratique, il y a peu de chance que cela ait un
effet non voulu).
Le masquage est une bonne idée (on doit supposer qu'il n'y a pas de bits
de padding, ce n'est donc pas idéal, mais c'est mieux que rien). Mieux,
faire un modulo, que le compilo sera capable d'optimiser si possible et
qui fonctionnera aussi si la taille n'est pas une puissance de 2.
- on caste (c) en (unsigned)
En quoi cela change quelque chose? (On suppose que c est positif, sinon
le décalage n'a pas de sens implicite.)
- on peut faire une expression sans test, ce qui generera un
meilleur code si le compilo est subtil.
Non, comportement indéfini (pire qu'avec le test).
Dans l'article <cjusr0$k5$1@news.tiscali.fr>,
Charlie Gordon <news@chqrlie.org> écrit:
La macro évidente :
#define SAFE_RSHIFT(v, c) ((sizeof(v)*CHAR_BIT >= (c)) ? 0 : (v) >>
(c))
- la comparaison est faite à l'envers, ce qui est facile à corriger ;-)
- on a potentiellement un comportement indéfini sur une partie de
l'expression.
- on a un warning stupide dans ce cas si c est constant et que le
compilateur se croit malin.
Ce n'est pas un warning stupide puisqu'il est justifié: comportement
indéfini (même si en pratique, il y a peu de chance que cela ait un
effet non voulu).
Le masquage est une bonne idée (on doit supposer qu'il n'y a pas de bits
de padding, ce n'est donc pas idéal, mais c'est mieux que rien). Mieux,
faire un modulo, que le compilo sera capable d'optimiser si possible et
qui fonctionnera aussi si la taille n'est pas une puissance de 2.
- on caste (c) en (unsigned)
En quoi cela change quelque chose? (On suppose que c est positif, sinon
le décalage n'a pas de sens implicite.)
- on peut faire une expression sans test, ce qui generera un
meilleur code si le compilo est subtil.
Non, comportement indéfini (pire qu'avec le test).
Dans l'article <cjusr0$k5$,
Charlie Gordon écrit:La macro évidente :
#define SAFE_RSHIFT(v, c) ((sizeof(v)*CHAR_BIT >= (c)) ? 0 : (v) >>
(c))
- la comparaison est faite à l'envers, ce qui est facile à corriger ;-)
- on a potentiellement un comportement indéfini sur une partie de
l'expression.
- on a un warning stupide dans ce cas si c est constant et que le
compilateur se croit malin.
Ce n'est pas un warning stupide puisqu'il est justifié: comportement
indéfini (même si en pratique, il y a peu de chance que cela ait un
effet non voulu).
Le masquage est une bonne idée (on doit supposer qu'il n'y a pas de bits
de padding, ce n'est donc pas idéal, mais c'est mieux que rien). Mieux,
faire un modulo, que le compilo sera capable d'optimiser si possible et
qui fonctionnera aussi si la taille n'est pas une puissance de 2.
- on caste (c) en (unsigned)
En quoi cela change quelque chose? (On suppose que c est positif, sinon
le décalage n'a pas de sens implicite.)
- on peut faire une expression sans test, ce qui generera un
meilleur code si le compilo est subtil.
Non, comportement indéfini (pire qu'avec le test).
Ce warning est stupide parce qu'il n'est produit que pour des valeurs
constantes de c qui sont plus grandes que la taille du type. Or le test
fait que le comportement indéfini n'est pas invoqué dans ce cas,
et le compilateur ne devrait même pas en générer le code puisque la
comparaison a un résultat connu à compile time.
Tu dis avoir eu ce warning, mais peut-être disparait-il quand tu
corriges le test inversé.
De quels bits de padding parles-tu ?
Et il faut impérativement caster (c) en (unsigned) pour que le
modulo soit toujours optimisé en un masque sur les architectures où
la taille est une puissance de 2 (connais-tu des contre-exemples ?),
sinon le code généré pour (c) expression signée non constante sera
inefficace.
- on caste (c) en (unsigned)
En quoi cela change quelque chose? (On suppose que c est positif, sinon
le décalage n'a pas de sens implicite.)
si c est une expression de type signé, par exemple une variable int,
le compilateur peut protester que la comparaison d'un int et d'un
size_t est suspecte, indépendemment du signe de la valeur qui doit
bien entendu être positive.
Le cast ne change pas la sémantique, il sert simplement à supprimer
le warning.
#define SAFE_SHR(v, c) (-(sizeof(v) * CHAR_BIT < (unsigned)(c)) & ((v) >>
((c) & (sizeof(v) * CHAR_BIT - 1)))
Avec cette version, le comportement n'est pas indéfini.
Ce warning est stupide parce qu'il n'est produit que pour des valeurs
constantes de c qui sont plus grandes que la taille du type. Or le test
fait que le comportement indéfini n'est pas invoqué dans ce cas,
et le compilateur ne devrait même pas en générer le code puisque la
comparaison a un résultat connu à compile time.
Tu dis avoir eu ce warning, mais peut-être disparait-il quand tu
corriges le test inversé.
De quels bits de padding parles-tu ?
Et il faut impérativement caster (c) en (unsigned) pour que le
modulo soit toujours optimisé en un masque sur les architectures où
la taille est une puissance de 2 (connais-tu des contre-exemples ?),
sinon le code généré pour (c) expression signée non constante sera
inefficace.
- on caste (c) en (unsigned)
En quoi cela change quelque chose? (On suppose que c est positif, sinon
le décalage n'a pas de sens implicite.)
si c est une expression de type signé, par exemple une variable int,
le compilateur peut protester que la comparaison d'un int et d'un
size_t est suspecte, indépendemment du signe de la valeur qui doit
bien entendu être positive.
Le cast ne change pas la sémantique, il sert simplement à supprimer
le warning.
#define SAFE_SHR(v, c) (-(sizeof(v) * CHAR_BIT < (unsigned)(c)) & ((v) >>
((c) & (sizeof(v) * CHAR_BIT - 1)))
Avec cette version, le comportement n'est pas indéfini.
Ce warning est stupide parce qu'il n'est produit que pour des valeurs
constantes de c qui sont plus grandes que la taille du type. Or le test
fait que le comportement indéfini n'est pas invoqué dans ce cas,
et le compilateur ne devrait même pas en générer le code puisque la
comparaison a un résultat connu à compile time.
Tu dis avoir eu ce warning, mais peut-être disparait-il quand tu
corriges le test inversé.
De quels bits de padding parles-tu ?
Et il faut impérativement caster (c) en (unsigned) pour que le
modulo soit toujours optimisé en un masque sur les architectures où
la taille est une puissance de 2 (connais-tu des contre-exemples ?),
sinon le code généré pour (c) expression signée non constante sera
inefficace.
- on caste (c) en (unsigned)
En quoi cela change quelque chose? (On suppose que c est positif, sinon
le décalage n'a pas de sens implicite.)
si c est une expression de type signé, par exemple une variable int,
le compilateur peut protester que la comparaison d'un int et d'un
size_t est suspecte, indépendemment du signe de la valeur qui doit
bien entendu être positive.
Le cast ne change pas la sémantique, il sert simplement à supprimer
le warning.
#define SAFE_SHR(v, c) (-(sizeof(v) * CHAR_BIT < (unsigned)(c)) & ((v) >>
((c) & (sizeof(v) * CHAR_BIT - 1)))
Avec cette version, le comportement n'est pas indéfini.
Si, comme dans l'exemple de Laurent Deniau, on teste la valeur pour
n'effectuer le décalage que si elle convient, il n'y a plus de
comportement indéfini. Ou alors j'ai manqué un épisode ?
Si, comme dans l'exemple de Laurent Deniau, on teste la valeur pour
n'effectuer le décalage que si elle convient, il n'y a plus de
comportement indéfini. Ou alors j'ai manqué un épisode ?
Si, comme dans l'exemple de Laurent Deniau, on teste la valeur pour
n'effectuer le décalage que si elle convient, il n'y a plus de
comportement indéfini. Ou alors j'ai manqué un épisode ?
Dans l'article <cjv6en$20n$,
Charlie Gordon écrit:Ce warning est stupide parce qu'il n'est produit que pour des valeurs
constantes de c qui sont plus grandes que la taille du type. Or le test
fait que le comportement indéfini n'est pas invoqué dans ce cas,
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.
Et il faut impérativement caster (c) en (unsigned) pour que le
modulo soit toujours optimisé en un masque sur les architectures où
la taille est une puissance de 2 (connais-tu des contre-exemples ?),
sinon le code généré pour (c) expression signée non constante sera
inefficace.
Faux. Le compilo peut très bien supposer que c est positif et donc
faire comme si c était non signé. Si c est strictement négatif, c'est
du comportement indéfini et ce n'était donc pas une erreur d'avoir
fait la supposition c >= 0.
- on caste (c) en (unsigned)
En quoi cela change quelque chose? (On suppose que c est positif,
sinon
le décalage n'a pas de sens implicite.)
si c est une expression de type signé, par exemple une variable int,
le compilateur peut protester que la comparaison d'un int et d'un
size_t est suspecte, indépendemment du signe de la valeur qui doit
bien entendu être positive.
Non, il n'a pas le droit de protester.
#define SAFE_SHR(v, c) (-(sizeof(v) * CHAR_BIT < (unsigned)(c)) & ((v)
((c) & (sizeof(v) * CHAR_BIT - 1)))
L'astuce du - est jolie, mais un peu obfuscated, et ne s'optimise
peut-être pas aussi bien qu'un ? :, mais je n'ai pas fait de test.
cmp eax,edx
Dans l'article <cjv6en$20n$1@news.tiscali.fr>,
Charlie Gordon <news@chqrlie.org> écrit:
Ce warning est stupide parce qu'il n'est produit que pour des valeurs
constantes de c qui sont plus grandes que la taille du type. Or le test
fait que le comportement indéfini n'est pas invoqué dans ce cas,
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.
Et il faut impérativement caster (c) en (unsigned) pour que le
modulo soit toujours optimisé en un masque sur les architectures où
la taille est une puissance de 2 (connais-tu des contre-exemples ?),
sinon le code généré pour (c) expression signée non constante sera
inefficace.
Faux. Le compilo peut très bien supposer que c est positif et donc
faire comme si c était non signé. Si c est strictement négatif, c'est
du comportement indéfini et ce n'était donc pas une erreur d'avoir
fait la supposition c >= 0.
- on caste (c) en (unsigned)
En quoi cela change quelque chose? (On suppose que c est positif,
sinon
le décalage n'a pas de sens implicite.)
si c est une expression de type signé, par exemple une variable int,
le compilateur peut protester que la comparaison d'un int et d'un
size_t est suspecte, indépendemment du signe de la valeur qui doit
bien entendu être positive.
Non, il n'a pas le droit de protester.
#define SAFE_SHR(v, c) (-(sizeof(v) * CHAR_BIT < (unsigned)(c)) & ((v)
((c) & (sizeof(v) * CHAR_BIT - 1)))
L'astuce du - est jolie, mais un peu obfuscated, et ne s'optimise
peut-être pas aussi bien qu'un ? :, mais je n'ai pas fait de test.
cmp eax,edx
Dans l'article <cjv6en$20n$,
Charlie Gordon écrit:Ce warning est stupide parce qu'il n'est produit que pour des valeurs
constantes de c qui sont plus grandes que la taille du type. Or le test
fait que le comportement indéfini n'est pas invoqué dans ce cas,
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.
Et il faut impérativement caster (c) en (unsigned) pour que le
modulo soit toujours optimisé en un masque sur les architectures où
la taille est une puissance de 2 (connais-tu des contre-exemples ?),
sinon le code généré pour (c) expression signée non constante sera
inefficace.
Faux. Le compilo peut très bien supposer que c est positif et donc
faire comme si c était non signé. Si c est strictement négatif, c'est
du comportement indéfini et ce n'était donc pas une erreur d'avoir
fait la supposition c >= 0.
- on caste (c) en (unsigned)
En quoi cela change quelque chose? (On suppose que c est positif,
sinon
le décalage n'a pas de sens implicite.)
si c est une expression de type signé, par exemple une variable int,
le compilateur peut protester que la comparaison d'un int et d'un
size_t est suspecte, indépendemment du signe de la valeur qui doit
bien entendu être positive.
Non, il n'a pas le droit de protester.
#define SAFE_SHR(v, c) (-(sizeof(v) * CHAR_BIT < (unsigned)(c)) & ((v)
((c) & (sizeof(v) * CHAR_BIT - 1)))
L'astuce du - est jolie, mais un peu obfuscated, et ne s'optimise
peut-être pas aussi bien qu'un ? :, mais je n'ai pas fait de test.
cmp eax,edx
"Vincent Lefevre" <vincent+ wrote in message
news:20041005221856$Dans l'article <cjv6en$20n$,
Charlie Gordon écrit:Ce warning est stupide parce qu'il n'est produit que pour des valeurs
constantes de c qui sont plus grandes que la taille du type. Or le
test
fait que le comportement indéfini n'est pas invoqué dans ce cas,
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.
Il peut considérer ce qu'il veut du terme indéfini, le test fait que
celui-ci n'est pas exécuté.
L'opérateur ?: n'évalue que 2 des 3 termes, et dans le cas présent il
n'évalue jamais le terme de droite dont le comportement est indéfini.
"Vincent Lefevre" <vincent+news@vinc17.org> wrote in message
news:20041005221856$0b97@vinc17.org...
Dans l'article <cjv6en$20n$1@news.tiscali.fr>,
Charlie Gordon <news@chqrlie.org> écrit:
Ce warning est stupide parce qu'il n'est produit que pour des valeurs
constantes de c qui sont plus grandes que la taille du type. Or le
test
fait que le comportement indéfini n'est pas invoqué dans ce cas,
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.
Il peut considérer ce qu'il veut du terme indéfini, le test fait que
celui-ci n'est pas exécuté.
L'opérateur ?: n'évalue que 2 des 3 termes, et dans le cas présent il
n'évalue jamais le terme de droite dont le comportement est indéfini.
"Vincent Lefevre" <vincent+ wrote in message
news:20041005221856$Dans l'article <cjv6en$20n$,
Charlie Gordon écrit:Ce warning est stupide parce qu'il n'est produit que pour des valeurs
constantes de c qui sont plus grandes que la taille du type. Or le
test
fait que le comportement indéfini n'est pas invoqué dans ce cas,
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.
Il peut considérer ce qu'il veut du terme indéfini, le test fait que
celui-ci n'est pas exécuté.
L'opérateur ?: n'évalue que 2 des 3 termes, et dans le cas présent il
n'évalue jamais le terme de droite dont le comportement est indéfini.