Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Evaluation d'une expression constante

31 réponses
Avatar
candide
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

10 réponses

1 2 3 4
Avatar
Erwan David
candide écrivait :

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("toton");

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 ?



Non. Cependant en pratique A*B sera évalué à la compilation.

--
Le travail n'est pas une bonne chose. Si ça l'était,
les riches l'auraient accaparé
Avatar
Charlie Gordon
"Erwan David" a écrit dans le message de news:

candide écrivait :

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("toton");

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 ?



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.
Avatar
Wykaaa
candide a écrit :
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("toton");

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


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.
Avatar
Antoine Leca
En news:49172a5f$0$17384$, 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("toton");
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("totontotontotontotontotontotontotontotontotontoto");
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("toton"); printf("toton"); printf("toton"); printf("toton");
printf("toton"); printf("toton"); printf("toton");
printf("toton"); printf("toton"); printf("toton");
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("totontotontotontotontotontotontotontotontotontoton");
return 0; }


Antoine
Avatar
Jean-Marc Bourguet
"Antoine Leca" writes:

En news:49172a5f$0$17384$, 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("toton");
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("totontotontotontotontotontotontotontotontotontoto");
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
Avatar
Vincent Lefevre
Dans l'article <gf9s85$rbc$,
Charlie Gordon é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 - 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)
Avatar
Antoine Leca
En news:20081113150454$, Vincent Lefevre va
escriure:
Dans l'article <gf9s85$rbc$,
Charlie Gordon é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
Avatar
Vincent Lefevre
Dans l'article <gfhpuk$vvu$,
Antoine Leca écrit:

En news:20081113150454$, Vincent Lefevre va
escriure:
> Dans l'article <gf9s85$rbc$,
> Charlie Gordon é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.



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

--
Vincent Lefèvre - 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)
Avatar
Mickaël Wolff
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
Avatar
Vincent Lefevre
Dans l'article <491cb231$0$8219$,
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, 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.

--
Vincent Lefèvre - 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)
1 2 3 4