Google Groupes n'accepte plus les nouveaux posts ni abonnements Usenet. Les contenus de l'historique resteront visibles.

Evaluation d'une expression constante

0 vue
Accéder directement au premier message non lu

candide

non lue,
9 nov. 2008, 13:22:2209/11/2008
à
Bonjour,

La norme dit :

6.6 Constant expressions
(...)
A constant expression can be evaluated during translation rather than
runtime,


Soit le programme suivant :

/*--------------------------------*/
#include <stdio.h>

#define A 2
#define B 5

int main(void)
{
int i;

for (i = 0; i < A * B; i++)
printf("toto\n");

return 0;
}
/*--------------------------------*/

Ai-je une quelconque garantie que l'expression A*B ne sera pas réévaluée
à chaque tour de boucle pendant l'exécution ?

Merci

Le message a été supprimé

Charlie Gordon

non lue,
10 nov. 2008, 12:49:5310/11/2008
à
"Erwan David" <er...@rail.eu.org> a écrit dans le message de news:
m21vxkk...@ratagaz.depot.rail.eu.org...
> candide <can...@free.invalid> écrivait :
> Non. Cependant en pratique A*B sera évalué à la compilation.

Je dirais même plus : on peut être quasi-sûr que ce sera le cas, pour 2
raisons:
- le compilateur est obligé de savoir faire l'évaluation des expressions
constantes au moment de la compilation, sinon impossible de déclarer ``char
a[A * B]''.
- si d'aventure ce n'était pas le cas, le résultat serait quand même 10, le
donc programme fonctionnerait correctement, et le manque de performance dû à
cette lacune du compilo serait le cadet de tes soucis, le code généré pour
le reste du programme étant vraisemblablement tout aussi inefficace.

Si tu as des doutes, tu peux toujours écrire

for (i = 0; i < sizeof(char[A * B]); i++) ...

Mais c'est un style particulièrement laid.

--
Chqrlie.


Wykaaa

non lue,
10 nov. 2008, 13:33:5710/11/2008
à
candide a écrit :
Un compilateur qui génèrerait du code pour réévaluer A*B a chaque tour
de boucle, il vaut mieux l'abandonner tout de suite parce que c'est
trivial à faire comme optimisation.

Antoine Leca

non lue,
11 nov. 2008, 04:09:1211/11/2008
à
En news:49172a5f$0$17384$426a...@news.free.fr, candide va escriure:

> #include <stdio.h>
> #define A 2
> #define B 5
> int main(void) {
> int i;
> for (i = 0; i < A * B; i++) printf("toto\n");
> return 0; }
>
> Ai-je une quelconque garantie que l'expression A*B ne sera pas
> réévaluée à chaque tour de boucle pendant l'exécution ?

Garantie formelle, non. D'ailleurs, tu n'as pas non plus de garantie que le
compilateur ou le processeur ne fasse pas 5 additions du nombre 2 à chaque
tour de boucle (tu as seulement la garantie qu'il ne va /pas/ passer par une
adition des logarithmes de 2 et de 5); tu n'as même pas de garantie qu'il y
ait effectivement une boucle.

J'ai déjà vu des compilateurs (pas C, mais c'est un détail) qui remplaçait à
la compilation le programme ci-dessus par

int main(void) {
puts("toto\ntoto\ntoto\ntoto\ntoto\ntoto\ntoto\ntoto\ntoto\ntoto");
return 0; }

Plus de i, plus de printf et un seul appel... Alors l'évaluation du produit
A*B, à ce niveau, c'est un détail de l'histoire...


En C, je ne pense pas que l'on rencontre de compilateur qui va sucrer
printf(), même si la norme le permet, parce qu'il est entré dans les mours
de pouvoir remplacer à l'édition des liens les fonctions de bibliothèque en
général, et malloc/free ou printf en particulier. Par contre, les
compilateurs optimisateurs vont dérouler la boucle, et réécrire le programme
ci-dessus sous la forme
int printf(const char*, ...);
int main(void) {
printf("toto\n"); printf("toto\n"); printf("toto\n"); printf("toto\n");
printf("toto\n"); printf("toto\n"); printf("toto\n");
printf("toto\n"); printf("toto\n"); printf("toto\n");
return 0; }
Et à partir de là, comme les compilateurs d'aujourd'hui ont des capacités
d'analyser les chaînes de format, il doit être possible de trouver un
compilateur qui vont fusionner les 10 chaînes de format entre elles, et
arriver à
int printf(const char*, ...);
int main(void) {
printf("toto\ntoto\ntoto\ntoto\ntoto\ntoto\ntoto\ntoto\ntoto\ntoto\n");
return 0; }


Antoine

Jean-Marc Bourguet

non lue,
11 nov. 2008, 05:18:5811/11/2008
à
"Antoine Leca" <ro...@localhost.invalid> writes:

> En news:49172a5f$0$17384$426a...@news.free.fr, candide va escriure:
>> #include <stdio.h>
>> #define A 2
>> #define B 5
>> int main(void) {
>> int i;
>> for (i = 0; i < A * B; i++) printf("toto\n");
>> return 0; }
>>
>> Ai-je une quelconque garantie que l'expression A*B ne sera pas
>> réévaluée à chaque tour de boucle pendant l'exécution ?
>
> Garantie formelle, non. D'ailleurs, tu n'as pas non plus de garantie que le
> compilateur ou le processeur ne fasse pas 5 additions du nombre 2 à chaque
> tour de boucle (tu as seulement la garantie qu'il ne va /pas/ passer par une
> adition des logarithmes de 2 et de 5); tu n'as même pas de garantie qu'il y
> ait effectivement une boucle.
>
> J'ai déjà vu des compilateurs (pas C, mais c'est un détail) qui remplaçait à
> la compilation le programme ci-dessus par
>
> int main(void) {
> puts("toto\ntoto\ntoto\ntoto\ntoto\ntoto\ntoto\ntoto\ntoto\ntoto");
> return 0; }
>
> Plus de i, plus de printf et un seul appel... Alors l'évaluation du produit
> A*B, à ce niveau, c'est un détail de l'histoire...

gcc arrive à

int main() {
puts("toto"); puts("toto"); puts("toto"); puts("toto"); puts("toto");
puts("toto"); puts("toto"); puts("toto"); puts("toto"); puts("toto");
return 0;
}

(Mais si je l'ai déjà vu supprimer du code mort ou remplacer des appels à
des fonctions standard par d'autres comme ici, je ne l'ai pas encore vu
fusionner des appels).

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Vincent Lefevre

non lue,
13 nov. 2008, 10:11:4213/11/2008
à
Dans l'article <gf9s85$rbc$1...@registered.motzarella.org>,
Charlie Gordon <ne...@chqrlie.org> écrit:

> - le compilateur est obligé de savoir faire l'évaluation des expressions
> constantes au moment de la compilation, sinon impossible de déclarer ``char
> a[A * B]''.

Euh... A * B pourrait très bien être effectué au lancement du
programme (même si ce n'est pas le cas en pratique).

--
Vincent Lefèvre <vin...@vinc17.org> - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)

Antoine Leca

non lue,
13 nov. 2008, 12:59:4813/11/2008
à
En news:20081113150454$27...@prunille.vinc17.org, Vincent Lefevre va
escriure:

> Dans l'article <gf9s85$rbc$1...@registered.motzarella.org>,
> Charlie Gordon <ne...@chqrlie.org> écrit:
>
>> - le compilateur est obligé de savoir faire l'évaluation des
>> expressions constantes au moment de la compilation, sinon impossible
>> de déclarer ``char a[A * B]''.
>
> Euh... A * B pourrait très bien être effectué au lancement du
> programme

Non. Si A*B donne une résultat négatif ou nul, le compilateur doit émettre
un diagnostic, ce qui impose de faire l'évaluation.


Antoine

Vincent Lefevre

non lue,
13 nov. 2008, 17:38:1213/11/2008
à
Dans l'article <gfhpuk$vvu$1...@shakotay.alphanet.ch>,
Antoine Leca <ro...@localhost.invalid> écrit:

On peut très bien détecter le signe du résultat sans effectuer le
produit!

Mickaël Wolff

non lue,
13 nov. 2008, 18:05:3913/11/2008
à
Vincent Lefevre a écrit :

> On peut très bien détecter le signe du résultat sans effectuer le
> produit!

En mathématique peut-être, mais en informatique pas forcément.
Surtout pas avec les nombres signés. Sans le calculer, c'est difficile
de savoir si (1 << 16) * 2 est positif ou négatif.

--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org

Vincent Lefevre

non lue,
14 nov. 2008, 04:28:5414/11/2008
à
Dans l'article <491cb231$0$8219$426a...@news.free.fr>,
Mickaël Wolff <mickae...@laposte.net> écrit:

> Vincent Lefevre a écrit :

> > On peut très bien détecter le signe du résultat sans effectuer le
> > produit!

> En mathématique peut-être, mais en informatique pas forcément.
> Surtout pas avec les nombres signés. Sans le calculer, c'est difficile
> de savoir si (1 << 16) * 2 est positif ou négatif.

1 est un entier signé positif, donc 1 << 16 est aussi positif, et
de même que (1 << 16) * 2. Rappel: il n'y a pas de wrapping sur
les entiers signés.

Mais bon, il suffit que le signe soit détectable dans certains
cas pour que dans ces cas-là, le compilateur ne soit pas obligé
d'effectuer le calcul à la compilation. Le compilateur peut aussi
émettre un diagnostic s'il estime que certains calculs sont trop
compliqués.

Michel Decima

non lue,
14 nov. 2008, 07:21:0714/11/2008
à
Vincent Lefevre a écrit :

> Dans l'article <491cb231$0$8219$426a...@news.free.fr>,
> Mickaël Wolff <mickae...@laposte.net> écrit:
>
>> Vincent Lefevre a écrit :
>
>>> On peut très bien détecter le signe du résultat sans effectuer le
>>> produit!
>
>> En mathématique peut-être, mais en informatique pas forcément.
>> Surtout pas avec les nombres signés. Sans le calculer, c'est difficile
>> de savoir si (1 << 16) * 2 est positif ou négatif.
>
> 1 est un entier signé positif, donc 1 << 16 est aussi positif, et
> de même que (1 << 16) * 2. Rappel: il n'y a pas de wrapping sur
> les entiers signés.

Est-ce que c'est vrai pour toutes les valeurs de 16 ?

void foo()
{
int tab[ ( 1 << 30 ) * 2 ] ;
}

$ gcc -c foo.c
foo.c: In function 'foo':
foo.c:3: warning: integer overflow in expression
foo.c:3: error: size of array 'tab' is negative

Vincent Lefevre

non lue,
16 nov. 2008, 20:51:5416/11/2008
à
Dans l'article <gfjqfj$g69$1...@news.rd.francetelecom.fr>,
Michel Decima <michel...@orange-ft.com> écrit:

> Est-ce que c'est vrai pour toutes les valeurs de 16 ?

Oui, toutes celles où l'expression est bien définie (pas d'overflow).

> void foo()
> {
> int tab[ ( 1 << 30 ) * 2 ] ;
> }

> $ gcc -c foo.c
> foo.c: In function 'foo':
> foo.c:3: warning: integer overflow in expression

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> foo.c:3: error: size of array 'tab' is negative

Cette erreur, c'est spécifique à l'implémentation, conséquence
de l'integer overflow. L'implémentation aurait très bien pu
choisir de donner une valeur positive à ( 1 << 30 ) * 2, auquel
cas le programme aurait pu être compilé (éventuellement sans
warning).

Michel Decima

non lue,
17 nov. 2008, 04:17:0217/11/2008
à
Vincent Lefevre a écrit :

> Dans l'article <gfjqfj$g69$1...@news.rd.francetelecom.fr>,
> Michel Decima <michel...@orange-ft.com> écrit:
>
>> Est-ce que c'est vrai pour toutes les valeurs de 16 ?
>
> Oui, toutes celles où l'expression est bien définie (pas d'overflow).

C'est bien ce que je voulais entendre, et cette notion d'overflow
n'apparaissait pas dans ta justification de (1<<16)*2 est positif.

Je reformule la remarque de Mickael en remplacant le verbe "calculer":

"Sans verifier que l'expression est bien definie sur la plateforme cible
(pas d'overflow), il est difficile de savoir si (1<<16)*2 est positif
ou negatif."

>
>> void foo()
>> {
>> int tab[ ( 1 << 30 ) * 2 ] ;
>> }
>
>> $ gcc -c foo.c
>> foo.c: In function 'foo':
>> foo.c:3: warning: integer overflow in expression
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
>> foo.c:3: error: size of array 'tab' is negative
>
> Cette erreur, c'est spécifique à l'implémentation, conséquence
> de l'integer overflow. L'implémentation aurait très bien pu
> choisir de donner une valeur positive à ( 1 << 30 ) * 2, auquel
> cas le programme aurait pu être compilé (éventuellement sans
> warning).

Oui. Connaissant l'implementation, j'ai choisi expres une grande valeur
de 16 pour provoquer l'apparition d'une valeur negative.

Je comprends bien que ce comportement est specifique a l'implementation,
mais j'observe la meme chose sur toutes les plateformes auquel j'ai
acces (linux/x86, hpux/ia64, aix/power). Evidemment, ca ne prouve rien
pour les autres ;)

Antoine Leca

non lue,
17 nov. 2008, 10:22:4117/11/2008
à
En news:20081117012443$23...@prunille.vinc17.org, Vincent Lefevre va
escriure:

> Dans l'article <gfjqfj$g69$1...@news.rd.francetelecom.fr>,
> Michel Decima écrit:

>
>> Est-ce que c'est vrai pour toutes les valeurs de 16 ?
>
> Oui, toutes celles où l'expression est bien définie (pas d'overflow).
<zap>

>> foo.c:3: warning: integer overflow in expression
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> foo.c:3: error: size of array 'tab' is negative
>
> Cette erreur, c'est spécifique à l'implémentation, conséquence
> de l'integer overflow.

Certes. Mais toute implémentation C aura une ou plusieurs limites (peu
importent les valeurs d'icelles).
Donc le compilateur sera bien obligé de faire l'évaluation A*B, justement
pour le cas où est franchie la dite limite de l'implémentation.

(Sans compter qu'il est plus facile de faire le calcul A*B que d'avoir à
gérer une table à je-ne-sais combien d'entrées, en fonction des types
respectifs de A et B, pour déterminer si le résultat est négatif ou nul.)


Antoine

Antoine Leca

non lue,
17 nov. 2008, 10:39:1617/11/2008
à
En news:20081114092411$21...@prunille.vinc17.org, Vincent Lefevre va
escriure:

> Dans l'article <491cb231$0$8219$426a...@news.free.fr>,
> Mickaël Wolff écrit:

>
>> Vincent Lefevre a écrit :
>
>>> On peut très bien détecter le signe du résultat sans effectuer le
>>> produit!
>
>> En mathématique peut-être, mais en informatique pas forcément.
>> Surtout pas avec les nombres signés. Sans le calculer, c'est
>> difficile de savoir si (1 << 16) * 2 est positif ou négatif.
>
> 1 est un entier signé positif,

Oui

> donc 1 << 16 est aussi positif, et de même que (1 << 16) * 2.


Pas forcément: cf. C99 6.1.3.1p3.


> Rappel: il n'y a pas de wrapping sur les entiers signés.

Sur ta machine peut-être (cela fait partie des choses définies par
l'implémentation, et je sais qu'il existe des machines à arithmétique
entière avec saturation, surtout en QN), mais ce n'est pas commun.


> Mais bon, il suffit que le signe soit détectable dans certains
> cas pour que dans ces cas-là, le compilateur ne soit pas obligé
> d'effectuer le calcul à la compilation.

Même si l'on effectue pas le calcul, cela reste une évaluation (au sens le
plus commun du terme).


Antoine

Vincent Lefevre

non lue,
17 nov. 2008, 12:58:3817/11/2008
à
Dans l'article <gfs377$pc5$1...@shakotay.alphanet.ch>,
Antoine Leca <ro...@localhost.invalid> écrit:

> En news:20081114092411$21...@prunille.vinc17.org, Vincent Lefevre va
> escriure:

> > donc 1 << 16 est aussi positif, et de même que (1 << 16) * 2.

> Pas forcément: cf. C99 6.1.3.1p3.

N'existe pas ici.

> > Rappel: il n'y a pas de wrapping sur les entiers signés.

> Sur ta machine peut-être (cela fait partie des choses définies par
> l'implémentation, et je sais qu'il existe des machines à arithmétique
> entière avec saturation, surtout en QN),

J'entendais par là: il n'y a pas de wrapping garanti.

> mais ce n'est pas commun.

Avec gcc, il faut -fwrapv pour qu'on soit sûr d'obtenir l'effet souhaité.

> > Mais bon, il suffit que le signe soit détectable dans certains
> > cas pour que dans ces cas-là, le compilateur ne soit pas obligé
> > d'effectuer le calcul à la compilation.

> Même si l'on effectue pas le calcul, cela reste une évaluation (au
> sens le plus commun du terme).

Le compilateur se comporte peut-être comme si c'était évalué (ça reste
bien flou), mais cela ne veut pas dire qu'il codera en dur le résultat
de l'évaluation.

Vincent Lefevre

non lue,
17 nov. 2008, 13:06:3717/11/2008
à
Dans l'article <gfrcqf$oht$1...@news.rd.francetelecom.fr>,
Michel Decima <michel...@orange-ft.com> écrit:

> Je reformule la remarque de Mickael en remplacant le verbe "calculer":

> "Sans verifier que l'expression est bien definie sur la plateforme cible
> (pas d'overflow), il est difficile de savoir si (1<<16)*2 est positif
> ou negatif."

Pas forcément. Ça dépend de la tête de l'expression. Par exemple, si
a, b et c sont positifs et qu'il n'y a pas d'overflow ni comportement
indéfini, alors (a << b) * c est positif. Un compilateur pourrait
très bien avoir ce genre de règles (e.g. s'il est conçu pour des
applications particulières...).

> Je comprends bien que ce comportement est specifique a l'implementation,
> mais j'observe la meme chose sur toutes les plateformes auquel j'ai
> acces (linux/x86, hpux/ia64, aix/power). Evidemment, ca ne prouve rien
> pour les autres ;)

Je suis d'accord que ça reste théorique, mais on a parfois des timings
surprenants.

Vincent Lefevre

non lue,
17 nov. 2008, 13:08:5117/11/2008
à
Dans l'article <gfs285$jgq$1...@shakotay.alphanet.ch>,
Antoine Leca <ro...@localhost.invalid> écrit:

> Donc le compilateur sera bien obligé de faire l'évaluation A*B, justement


> pour le cas où est franchie la dite limite de l'implémentation.

Pas obligé, même si c'est ce qui est le plus probable.

> (Sans compter qu'il est plus facile de faire le calcul A*B que d'avoir à
> gérer une table à je-ne-sais combien d'entrées, en fonction des types
> respectifs de A et B, pour déterminer si le résultat est négatif ou nul.)

Pas forcément (e.g. avec une application particulière et un compilateur
associé, où A et B ont des formes particulières).

Antoine Leca

non lue,
21 nov. 2008, 13:00:1521/11/2008
à
En news:20081117175312$32...@prunille.vinc17.org, Vincent Lefevre va
escriure:

>> donc 1 << 16 est aussi positif, et de même que (1 << 16) * 2.
>> Pas forcément: cf. C99 6.1.3.1p3.
>
> N'existe pas ici.

Exact, il fallait lire 6.3.1.3p3.


> Le compilateur se comporte peut-être comme si c'était évalué (ça reste
> bien flou), mais cela ne veut pas dire qu'il codera en dur le résultat
> de l'évaluation.

Mais je n'ai jamais dit ni même sous-entendu qu'il n'était pas possible de
(re)faire l'évaluation au moment de l'exécution.
Voire même comme le proposait Marc, de faire trois évaluations distinctes et
de choisir la plus « sûre ».


Ton propos initial était de refuser l'argument de l'article
<gf9s85$rbc$1...@registered.motzarella.org>, où Charlie Gordon
<ne...@chqrlie.org> écrit:

: - le compilateur est obligé de savoir faire l'évaluation des expressions
: constantes au moment de la compilation, sinon impossible de déclarer
``char
: a[A * B]''.

Moi je dis qu'il est effectivement bien obligé, histoire d'attraper un truc
comme

#include<limits.h>
#define A 2
#define B (INT_MAX+1u)
char a[A*B];


(et oui, je sais qu'en théorie C99 il y a des machines où INT_MAX+1u n'est
PAS la moitié de UINT_MAX+1, dans ce cas merci de remplacer A dans
l'expression ci-dessus par la puissance de 2 appropriée.)


Antoine

Vincent Lefevre

non lue,
21 nov. 2008, 16:47:0821/11/2008
à
Dans l'article <gg6svg$rle$1...@shakotay.alphanet.ch>,
Antoine Leca <ro...@localhost.invalid> écrit:

> En news:20081117175312$32...@prunille.vinc17.org, Vincent Lefevre va
> escriure:

> >> donc 1 << 16 est aussi positif, et de même que (1 << 16) * 2.
> >> Pas forcément: cf. C99 6.1.3.1p3.
> >
> > N'existe pas ici.

> Exact, il fallait lire 6.3.1.3p3.

Attends, ceci concerne les *conversions*. Ici, pas de conversion. Les
règles pour les opérations, style * (multiplication), sont différentes.
Cf 6.5#5: c'est de l'undefined behavior.

> Ton propos initial était de refuser l'argument de l'article
> <gf9s85$rbc$1...@registered.motzarella.org>, où Charlie Gordon
> <ne...@chqrlie.org> écrit:

> : - le compilateur est obligé de savoir faire l'évaluation des expressions
> : constantes au moment de la compilation, sinon impossible de déclarer
> ``char
> : a[A * B]''.

> Moi je dis qu'il est effectivement bien obligé, histoire d'attraper un truc
> comme

> #include<limits.h>
> #define A 2
> #define B (INT_MAX+1u)
> char a[A*B];

Un exemple n'a jamais rien prouvé sur le cas général. Le point
important est qu'il *existe* des expressions constantes que le
compilateur n'a pas besoin d'évaluer complètement (i.e. d'en
connaître le résultat) pour qu'il se comporte de manière conforme
à la norme. De telles expressions constantes peuvent alors très
bien être évaluées à l'exécution.

Par exemple, pour A*B sur du non signé, on peut raisonner sur la
valuation 2-adique.

Vincent Lefevre

non lue,
21 nov. 2008, 16:57:3721/11/2008
à
Dans l'article <gg6svg$rle$1...@shakotay.alphanet.ch>,
Antoine Leca <ro...@localhost.invalid> écrit:

> Moi je dis qu'il est effectivement bien obligé, histoire d'attraper un truc
> comme

> #include<limits.h>
> #define A 2
> #define B (INT_MAX+1u)
> char a[A*B];

D'autre part, si "char a[A*B];" se trouve dans une fonction (qui
pourrait ne jamais être appelée), doit-on avoir un diagnostic?

Antoine Leca

non lue,
25 nov. 2008, 05:28:2425/11/2008
à
En news:20081121212730$32...@prunille.vinc17.org, Vincent Lefevre va
escriure:

> Dans l'article <gg6svg$rle$1...@shakotay.alphanet.ch>,
> Antoine Leca <ro...@localhost.invalid> écrit:
>
>> En news:20081117175312$32...@prunille.vinc17.org, Vincent Lefevre va
>> escriure:
>
>>>> donc 1 << 16 est aussi positif, et de même que (1 << 16) * 2.
>>>> Pas forcément: cf. C99 6.3.1.3p3.

>
> Attends, ceci concerne les *conversions*. Ici, pas de conversion.
> Les règles pour les opérations, style * (multiplication), sont
> différentes.
> Cf 6.5#5: c'est de l'undefined behavior.

Je ne prendrais pas cet argument trop au pied de la lettre: en supposant


#include<limits.h>
#define A 2
#define B (INT_MAX+1u)

6.5p5 revient à dire que le résultat de A*B a un comportement indéfini, car
il est en dehors des valeurs représentables pour le type unsigned int (dans
le cas général) ; même punition pour UINT_MAX+1 ou -1u ; auquel cas il y a
pas mal de code C qui est complètement inutilisable...

Pour que cela marche comme attendu, il faut appliquer 6.3p1 et 6.3.1.8 aux
opérations de la clause 6.5 (après les spécifiques genre 6.5.7p3 mais avant
6.5p5).


>> Ton propos initial était de refuser l'argument de l'article
>> <gf9s85$rbc$1...@registered.motzarella.org>, où Charlie Gordon
>> <ne...@chqrlie.org> écrit:
>>> - le compilateur est obligé de savoir faire l'évaluation des
>>> expressions constantes au moment de la compilation, sinon
>>> impossible de déclarer ``char a[A * B]''.
>

> Un exemple n'a jamais rien prouvé sur le cas général. Le point
> important est qu'il *existe* des expressions constantes que le
> compilateur n'a pas besoin d'évaluer complètement (i.e. d'en
> connaître le résultat) pour qu'il se comporte de manière conforme
> à la norme.

Je ne suis pas d'accord avec ta logique, que je lis comme : il existe au
moins une expression constante pour laquelle un compilateur peut se
permettre de ne pas calculer la valeur au moment de la compilation, donc il
n'est pas obligé de savoir faire l'évaluation des expressions constantes.

Pour moi c'est plutôt : il existe au moins une classe d'expression pour
laquelle le compilateur est (raisonnablement) obligé de calculer une
estimation de la valeur dès la compilation, afin d'émettre les diagnostics
requis par la norme.


> De telles expressions constantes peuvent alors très
> bien être évaluées à l'exécution.

Encore une fois, personne ne nie cela, au contraire cela a été la première
réponse d'Erwan, de Marc B., ou de moi-même. Et on peut inférer de la
réponse de Wykaaa qu'il est d'acord aussi.


> Par exemple, pour A*B sur du non signé, on peut raisonner sur la
> valuation 2-adique.

J'ai déjà répondu à cela. On peut toujours inventer des manières de ne pas
calculer le produit, mais cela revient quand même à faire une évaluation de
sa valeur, ici savoir si elle est nulle (c'est même probablement pour cela
que la norme utilise le terme « évaluation » au lieu de « calcul »).


> D'autre part, si "char a[A*B];" se trouve dans une fonction (qui
> pourrait ne jamais être appelée), doit-on avoir un diagnostic?

Je dirais que oui, cf 5.1.1.3, et la formulation de 6.10.1p5 qui cherche
(peut-être imparfaitement) à autoriser une syntaxe invalide à être présente
dans un groupe sauté par #if 0 ou similaire.


Antoine

Vincent Lefevre

non lue,
25 nov. 2008, 12:20:4325/11/2008
à
Dans l'article <gggk09$7vq$1...@shakotay.alphanet.ch>,
Antoine Leca <ro...@localhost.invalid> écrit:

> 6.5p5 revient à dire que le résultat de A*B a un comportement indéfini, car


> il est en dehors des valeurs représentables pour le type unsigned int (dans
> le cas général) ; même punition pour UINT_MAX+1 ou -1u ;

Pourquoi UINT_MAX+1 est-il du comportement indéfini? Il n'y a pas
d'overflow sur du ***non signé***. Alors je ne comprends pas.

En revanche, je serais d'accord pour INT_MAX+1: comportement indéfini.

> auquel cas il y a pas mal de code C qui est complètement
> inutilisable...

On a déjà vu ce que donnait du code C mal écrit. De toute façon
là n'est pas la question. Du comportement indéfini reste du
comportement indéfini, même si beaucoup de code C suppose un
comportement particulier. Le compilateur peut toujours compiler
du comportement indéfini de façon à ce qu'on obtienne le
comportement attendu par l'utilisateur (style -fwrapv).

> Je ne suis pas d'accord avec ta logique, que je lis comme : il existe au
> moins une expression constante pour laquelle un compilateur peut se
> permettre de ne pas calculer la valeur au moment de la compilation, donc il
> n'est pas obligé de savoir faire l'évaluation des expressions constantes.

Pas de *toutes* les expressions constantes. [Attention à la négation
du "pour tout".]

> > De telles expressions constantes peuvent alors très
> > bien être évaluées à l'exécution.

> Encore une fois, personne ne nie cela, au contraire cela a été la première
> réponse d'Erwan, de Marc B., ou de moi-même. Et on peut inférer de la
> réponse de Wykaaa qu'il est d'acord aussi.

Pourtant Charlie a dit:

| le compilateur est obligé de savoir faire l'évaluation des expressions
| constantes au moment de la compilation, sinon impossible de déclarer
| ``char a[A * B]''.

Moi je dis:
Avec un compilateur qui ne sait pas faire l'évaluation de toutes les
expressions constantes, il n'est pas forcément impossible de déclarer


``char a[A * B]''.

> > Par exemple, pour A*B sur du non signé, on peut raisonner sur la
> > valuation 2-adique.

> J'ai déjà répondu à cela. On peut toujours inventer des manières de ne pas
> calculer le produit, mais cela revient quand même à faire une évaluation de
> sa valeur,

Cela revient au même au niveau de la sémantique, mais pas au niveau
du temps de calcul (même si la norme ne se préoccupe pas du temps
de calcul, cette question d'implémentation était dans la question
initiale).

Il y a des raisonnements qui risquent de ne pas tenir si on considère
une implémentation avec des types int sur des milliers de bits (c'est
autorisé par la norme, et ça pourrait être utile en pratique).

> > D'autre part, si "char a[A*B];" se trouve dans une fonction (qui
> > pourrait ne jamais être appelée), doit-on avoir un diagnostic?

> Je dirais que oui, cf 5.1.1.3, et la formulation de 6.10.1p5 qui cherche
> (peut-être imparfaitement) à autoriser une syntaxe invalide à être présente
> dans un groupe sauté par #if 0 ou similaire.

Alors comment ça se fait que lorsque la contrainte 6.6#4 "Each
constant expression shall evaluate to a constant that is in the
range of representable values for its type." est violée, gcc
n'émet pas toujours un diagnostic? Bug?

Le problème se produit avec une expression constante du style
((1 << 20) * (1 << 20))

Par exemple (sur une machine 32 bits) pour:

int main(void)
{
int x;
x = 0 && ((1 << 20) * (1 << 20));
return 0;
}

En revanche, gcc donne bien le diagnostic pour:

int main(void)
{
int x;
if (0)
x = ((1 << 20) * (1 << 20));
return 0;

Antoine Leca

non lue,
26 nov. 2008, 14:17:0726/11/2008
à
En news:20081125164122$0a...@prunille.vinc17.org, Vincent Lefevre va
escriure:

> Dans l'article <gggk09$7vq$1...@shakotay.alphanet.ch>,
> Antoine Leca <ro...@localhost.invalid> écrit:
>
>> 6.5p5 revient à dire que le résultat de A*B a un comportement
>> indéfini, car il est en dehors des valeurs représentables pour le
>> type unsigned int (dans le cas général) ; même punition pour
>> UINT_MAX+1 ou -1u ;
>
> Pourquoi UINT_MAX+1 est-il du comportement indéfini? Il n'y a pas
> d'overflow sur du ***non signé***.

En vertu de quoi ?


> Alors je ne comprends pas.

Moi non plus.
Si je lis 6.5p5 (sans considérer 6.3), le résultat brut d'une opération hors
du domaine des valeurs représentables aurait un comportement indéfini.
UINT_MAX+1 est en dehors du domaine des valeurs représentables pour un
unsigned int. -1 non plus ne fait pas partie de ces valeurs.


>> Je ne suis pas d'accord avec ta logique, que je lis comme : il
>> existe au moins une expression constante pour laquelle un
>> compilateur peut se permettre de ne pas calculer la valeur au moment
>> de la compilation, donc il n'est pas obligé de savoir faire
>> l'évaluation des expressions constantes.
>
> Pas de *toutes* les expressions constantes. [Attention à la négation
> du "pour tout".]

Seul souci, je ne localise pas le « pour tout » dans ce fil non plus
(décidément, ce mois-ci on dirait que j'ai du mal avec les mathématiques).


> Pourtant Charlie a dit:
>> le compilateur est obligé de savoir faire l'évaluation des
>> expressions constantes au moment de la compilation, sinon impossible
>> de déclarer ``char a[A * B]''.
>
> Moi je dis:
> Avec un compilateur qui ne sait pas faire l'évaluation de toutes les
> expressions constantes, il n'est pas forcément impossible de
> déclarer ``char a[A * B]''.

Donc vous dites deux choses deux choses distinctes : Chqrlie que le
compilateur _doit_ savoir évaluer [certaines] expressions, et toi qu'il lui
est loisible de ne pas les évaluer _toutes_.

(Le « [certaines] » est dans news:gfhpuk$vvu$1...@shakotay.alphanet.ch.)


> Cela revient au même au niveau de la sémantique, mais pas au niveau
> du temps de calcul (même si la norme ne se préoccupe pas du temps
> de calcul, cette question d'implémentation était dans la question
> initiale).

Je n'avais pas vu que la question initiale se préoccupe du temps de calcul
*pendant la compilation*.


> Alors comment ça se fait que lorsque la contrainte 6.6#4 "Each
> constant expression shall evaluate to a constant that is in the
> range of representable values for its type." est violée, gcc
> n'émet pas toujours un diagnostic? Bug?

http://www.open-std.org/JTC1/SC22/WG14/www/docs/dr_261.htm répond-t-il à ta
question ?

Si non, bogue ou DR.


Antoine

Vincent Lefevre

non lue,
28 nov. 2008, 13:29:5328/11/2008
à
Dans l'article <ggk7bl$j5e$1...@shakotay.alphanet.ch>,
Antoine Leca <ro...@localhost.invalid> écrit:

> En news:20081125164122$0a...@prunille.vinc17.org, Vincent Lefevre va
> escriure:
> > Dans l'article <gggk09$7vq$1...@shakotay.alphanet.ch>,
> > Antoine Leca <ro...@localhost.invalid> écrit:
> >
> >> 6.5p5 revient à dire que le résultat de A*B a un comportement
> >> indéfini, car il est en dehors des valeurs représentables pour le
> >> type unsigned int (dans le cas général) ; même punition pour
> >> UINT_MAX+1 ou -1u ;
> >
> > Pourquoi UINT_MAX+1 est-il du comportement indéfini? Il n'y a pas
> > d'overflow sur du ***non signé***.

> En vertu de quoi ?

6.2.5. Je cite: "A computation involving unsigned operands can never
overflow, because a result that cannot be represented by the resulting
unsigned integer type is reduced modulo the number that is one greater
than the largest value that can be represented by the resulting type."

> > Alors je ne comprends pas.

> Moi non plus.
> Si je lis 6.5p5 (sans considérer 6.3), le résultat brut d'une opération hors
> du domaine des valeurs représentables aurait un comportement indéfini.

Non, c'est 6.2.5 qui garantit le comportement bien défini (pas besoin de
considérer 6.3, qui ne concerne que les conversions).

> >> Je ne suis pas d'accord avec ta logique, que je lis comme : il
> >> existe au moins une expression constante pour laquelle un
> >> compilateur peut se permettre de ne pas calculer la valeur au moment
> >> de la compilation, donc il n'est pas obligé de savoir faire
> >> l'évaluation des expressions constantes.
> >
> > Pas de *toutes* les expressions constantes. [Attention à la négation
> > du "pour tout".]

> Seul souci, je ne localise pas le « pour tout » dans ce fil non plus
> (décidément, ce mois-ci on dirait que j'ai du mal avec les mathématiques).

J'ai supposé que le "pour tout" était implicite, pour que le
raisonnement logique soit correct (i.e. Charlie n'aurait rien
pu déduire sur l'expression *particulière* donnée dans l'exemple).

> > Pourtant Charlie a dit:
> >> le compilateur est obligé de savoir faire l'évaluation des
> >> expressions constantes au moment de la compilation, sinon impossible
> >> de déclarer ``char a[A * B]''.
> >
> > Moi je dis:
> > Avec un compilateur qui ne sait pas faire l'évaluation de toutes les
> > expressions constantes, il n'est pas forcément impossible de
> > déclarer ``char a[A * B]''.

> Donc vous dites deux choses deux choses distinctes : Chqrlie que le
> compilateur _doit_ savoir évaluer [certaines] expressions, et toi qu'il lui
> est loisible de ne pas les évaluer _toutes_.

Cf ci-dessus.

> > Alors comment ça se fait que lorsque la contrainte 6.6#4 "Each
> > constant expression shall evaluate to a constant that is in the
> > range of representable values for its type." est violée, gcc
> > n'émet pas toujours un diagnostic? Bug?

Il va falloir que je regarde de près, mais je n'ai pas l'impression que
ça répond à ma question sans poser des problèmes avec d'autres parties
de la norme.

Charlie Gordon

non lue,
28 nov. 2008, 13:50:5628/11/2008
à
"Antoine Leca" <ro...@localhost.invalid> a écrit dans le message de news:
ggk7bl$j5e$1...@shakotay.alphanet.ch...

> En news:20081125164122$0a...@prunille.vinc17.org, Vincent Lefevre va
> escriure:
>> Dans l'article <gggk09$7vq$1...@shakotay.alphanet.ch>,
>> Antoine Leca <ro...@localhost.invalid> écrit:
>>
>>> 6.5p5 revient à dire que le résultat de A*B a un comportement
>>> indéfini, car il est en dehors des valeurs représentables pour le
>>> type unsigned int (dans le cas général) ; même punition pour
>>> UINT_MAX+1 ou -1u ;
>>
>> Pourquoi UINT_MAX+1 est-il du comportement indéfini? Il n'y a pas
>> d'overflow sur du ***non signé***.
>
> En vertu de quoi ?

L'arithmetique sur les entiers non signés est définie par la norme : le
calcul se fait modulo 2 puissance n ou n est le nombre de bits significatifs
de valeur. On en déduit que UINT_MAX+1 vaut 0.

>> Alors je ne comprends pas.
>
> Moi non plus.
> Si je lis 6.5p5 (sans considérer 6.3), le résultat brut d'une opération
> hors
> du domaine des valeurs représentables aurait un comportement indéfini.
> UINT_MAX+1 est en dehors du domaine des valeurs représentables pour un
> unsigned int. -1 non plus ne fait pas partie de ces valeurs.

-1U vaut exactement UINT_MAX, pour la même raison que ci-dessus.

Pour les experts, notons tout de même que le préprocesseur évalue les
expressions de contrôle des blocs conditionnels #if et #elif comme si tous
les types entiers signés (resp. non signés) étaient identiques à intmax_t
(resp. uintmax_t). Donc l'expression de contrôle UINT_MAX+1 est non nulle
sauf dans le cas très particulier où UINT_MAX == UINTMAX_MAX, c'est à dire
que int et intmax_t ont la même représentation, ce qui implique que long et
long long aient aussi cette représentation et donc fasse au moins 64 bits,
dans ce cas seulement, #if UINT_MAX+1 s'évalue comme #if 0

...


>> Pourtant Charlie a dit:
>>> le compilateur est obligé de savoir faire l'évaluation des
>>> expressions constantes au moment de la compilation, sinon impossible
>>> de déclarer ``char a[A * B]''.
>>
>> Moi je dis:
>> Avec un compilateur qui ne sait pas faire l'évaluation de toutes les
>> expressions constantes, il n'est pas forcément impossible de
>> déclarer ``char a[A * B]''.
>
> Donc vous dites deux choses deux choses distinctes : Chqrlie que le
> compilateur _doit_ savoir évaluer [certaines] expressions, et toi qu'il
> lui
> est loisible de ne pas les évaluer _toutes_.

En fait la deuxième affirmation est mal formulée : "un compilateur qui ne
sait pas faire l'évaluation de toutes les expressions contantes" ne me
semble pas conforme à la norme, en revanche rien n'oblige un compilateur
conforme à faire l'évaluation des expressions constantes à la compilation
dans les cas où cela n'est pas nécessaire pour compiler du code conforme,
mais que gagnerait le compilateur à ne pas faire cette optimisation simple ?
Même tcc fait le constant folding.

--
Chqrlie.


Vincent Lefevre

non lue,
28 nov. 2008, 18:42:5528/11/2008
à
Dans l'article <ggpeii$6ld$1...@news.motzarella.org>,
Charlie Gordon <ne...@chqrlie.org> écrit:

> "Antoine Leca" <ro...@localhost.invalid> a écrit dans le message de news:

> ggk7bl$j5e$1...@shakotay.alphanet.ch...
> > En news:20081125164122$0a...@prunille.vinc17.org, Vincent Lefevre va
> > escriure:
> >> Dans l'article <gggk09$7vq$1...@shakotay.alphanet.ch>,
> >> Antoine Leca <ro...@localhost.invalid> écrit:

> ...


> >> Pourtant Charlie a dit:
> >>> le compilateur est obligé de savoir faire l'évaluation des
> >>> expressions constantes au moment de la compilation, sinon impossible
> >>> de déclarer ``char a[A * B]''.
> >>
> >> Moi je dis:
> >> Avec un compilateur qui ne sait pas faire l'évaluation de toutes les
> >> expressions constantes, il n'est pas forcément impossible de
> >> déclarer ``char a[A * B]''.
> >
> > Donc vous dites deux choses deux choses distinctes : Chqrlie que
> > le compilateur _doit_ savoir évaluer [certaines] expressions, et
> > toi qu'il lui est loisible de ne pas les évaluer _toutes_.

> En fait la deuxième affirmation est mal formulée : "un compilateur qui ne
> sait pas faire l'évaluation de toutes les expressions contantes" ne me
> semble pas conforme à la norme,

Je ne suis pas d'accord. De toute façon, je me rend compte maintenant
que c'est stupide: dans la pratique, aucun compilateur ne sait évaluer
toutes les expressions constantes, car on peut toujours lui fournir
quelque chose de tellement compliqué qu'on va faire exploser les
limites de la machine. :) (Et aucune implémentation n'est évidemment
requise de traduire tout programme conforme.)

Mais cela conforte ce que j'ai dit (les limites de la machine étant
une notion floue): on peut très bien supposer que le compilateur ne
sait évaluer aucune expression constante (autre que les constantes),
le cas A * B pouvant se résoudre par un calcul de valuation 2-adique.
Un tel compilateur va râler sur de nombreux programmes conformes, mais
certainement pas à cause de ``char a[A * B]''.

> en revanche rien n'oblige un compilateur conforme à faire
> l'évaluation des expressions constantes à la compilation dans les
> cas où cela n'est pas nécessaire pour compiler du code conforme,
> mais que gagnerait le compilateur à ne pas faire cette optimisation
> simple ?

On peut faire des justifications très tordues sur des implémentations
possibles, mais qui n'existent pas en pratique.

Mais déjà, l'évaluation de constantes flottantes (i.e. la conversion
base 10 -> base 2) est un problème assez compliqué[*], et si le
compilateur sait que certaines constantes ne seront probablement pas
évaluées, il peut laisser l'évaluation éventuelle à l'exécution afin
d'avoir un temps de compilation plus court.

[*] au point que certaines implémentations sont buggées, cf par exemple:

http://sourceware.org/bugzilla/show_bug.cgi?id=3479

et (mentionné dans ce bug de la glibc):

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21718

Vincent Lefevre

non lue,
28 nov. 2008, 18:44:2528/11/2008
à
Dans l'article <ggpeii$6ld$1...@news.motzarella.org>,
Charlie Gordon <ne...@chqrlie.org> écrit:

> "Antoine Leca" <ro...@localhost.invalid> a écrit dans le message de news:

> ggk7bl$j5e$1...@shakotay.alphanet.ch...
> > En news:20081125164122$0a...@prunille.vinc17.org, Vincent Lefevre va
> > escriure:
> >> Dans l'article <gggk09$7vq$1...@shakotay.alphanet.ch>,
> >> Antoine Leca <ro...@localhost.invalid> écrit:

> ...


> >> Pourtant Charlie a dit:
> >>> le compilateur est obligé de savoir faire l'évaluation des
> >>> expressions constantes au moment de la compilation, sinon impossible
> >>> de déclarer ``char a[A * B]''.
> >>
> >> Moi je dis:
> >> Avec un compilateur qui ne sait pas faire l'évaluation de toutes les
> >> expressions constantes, il n'est pas forcément impossible de
> >> déclarer ``char a[A * B]''.
> >
> > Donc vous dites deux choses deux choses distinctes : Chqrlie que
> > le compilateur _doit_ savoir évaluer [certaines] expressions, et
> > toi qu'il lui est loisible de ne pas les évaluer _toutes_.

> En fait la deuxième affirmation est mal formulée : "un compilateur qui ne
> sait pas faire l'évaluation de toutes les expressions contantes" ne me
> semble pas conforme à la norme,

Je ne suis pas d'accord. De toute façon, je me rends compte maintenant


que c'est stupide: dans la pratique, aucun compilateur ne sait évaluer
toutes les expressions constantes, car on peut toujours lui fournir
quelque chose de tellement compliqué qu'on va faire exploser les
limites de la machine. :) (Et aucune implémentation n'est évidemment
requise de traduire tout programme conforme.)

Mais cela conforte ce que j'ai dit (les limites de la machine étant
une notion floue): on peut très bien supposer que le compilateur ne
sait évaluer aucune expression constante (autre que les constantes),
le cas A * B pouvant se résoudre par un calcul de valuation 2-adique.
Un tel compilateur va râler sur de nombreux programmes conformes, mais

certainement pas à cause de ``char a[A * B]''.

> en revanche rien n'oblige un compilateur conforme à faire
> l'évaluation des expressions constantes à la compilation dans les
> cas où cela n'est pas nécessaire pour compiler du code conforme,
> mais que gagnerait le compilateur à ne pas faire cette optimisation
> simple ?

On peut faire des justifications très tordues sur des implémentations


possibles, mais qui n'existent pas en pratique.

Mais déjà, l'évaluation de constantes flottantes (i.e. la conversion
base 10 -> base 2) est un problème assez compliqué[*], et si le
compilateur sait que certaines constantes ne seront probablement pas
évaluées, il peut laisser l'évaluation éventuelle à l'exécution afin
d'avoir un temps de compilation plus court.

[*] au point que certaines implémentations sont buggées, cf par exemple:

http://sourceware.org/bugzilla/show_bug.cgi?id=3479

et (mentionné dans ce bug de la glibc):

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21718

--

Vincent Lefevre

non lue,
28 nov. 2008, 19:09:3228/11/2008
à
Dans l'article <ggk7bl$j5e$1...@shakotay.alphanet.ch>,
Antoine Leca <ro...@localhost.invalid> écrit:

> > Alors comment ça se fait que lorsque la contrainte 6.6#4 "Each


> > constant expression shall evaluate to a constant that is in the
> > range of representable values for its type." est violée, gcc
> > n'émet pas toujours un diagnostic? Bug?

D'accord, si je comprends bien, il y a une interprétation valide
en considérant que ((1 << 20) * (1 << 20)) n'est pas une expression
constante, donc on ne considère pas que c'est une expression
constante qui viole une contrainte.

Marc Espie

non lue,
29 nov. 2008, 05:27:1029/11/2008
à
In article <20081128234414$06...@prunille.vinc17.org>,

Il me semble justement qu'il y a un bout de paragraphe tout au debut de
la norme qui fixe ces limites (longueur maximale d'expression, niveau
de parentheses etc). J'aurais un peu tendance a penser que tu pipotes.

A cote de ca, il n'existe certainement aucune implementation completement
conforme. On est dans le vrai monde, et elles ont toutes des bugs.

Vincent Lefevre

non lue,
29 nov. 2008, 17:18:3229/11/2008
à
Dans l'article <ggr5du$2bu3$1...@biggoron.nerim.net>,
Marc Espie <es...@lain.home> écrit:

> Il me semble justement qu'il y a un bout de paragraphe tout au debut de
> la norme qui fixe ces limites (longueur maximale d'expression, niveau
> de parentheses etc). J'aurais un peu tendance a penser que tu pipotes.

Au lieu de dire que je pipote, tu ferais mieux de lire ce que dit
exactement la norme:

The implementation shall be able to translate and execute at least
one program that contains at least one instance of every one of the
following limits:

"at least one", cela ne signifie pas tous les programmes.

0 nouveau message