Salut,
cette réflection m'a interpelé ... il est fort quand même gcc, il voit floor dans <math.h> (dans la glibc/gcc il y a un attribut const qui signifie même paramêtre -> même résultat). Il optimise en exécutant un floor(1.1) (donc en faisant appel à la libm) et place le résultat à la place de l'appel de fonction. Ça me paraît cohérent.
Mais que se passe-t-il si on remplace (maladroitement) le #include <math.h> par le prototype naïf de floor :
1 2 3 4 5 6 7 8 9 10
| // test.c
#include <stdio.h>
//#include <math.h>
extern double floor(double);
int main () {
printf ("floor 1.1 : %f\n", floor(1.1)) ;
return 0 ;
} |
Pas d'attribut const cette fois ci ... donc l'appel à floor pourrait faire autre chose que renvoyer une valeur constante pour un paramètre constant (comme modifier une variable globale, renvoyer une valeur non constante, ...).
1 2 3 4 5 6 7
| ~> gcc -o test test.c
~> ldd test
linux-vdso.so.1 => (0x00007fff995ff000)
libc.so.6 => /lib64/libc.so.6 (0x00007f39f9891000)
/lib64/ld-linux-x86-64.so.2 (0x00007f39f9c21000)
~> ./test
floor 1.1 : 1.000000 |
Ah ben non .... toujours la même optimisation ?
Mais alors que se passerait-il si je lui donne ma version de floor ?
1 2 3 4 5 6
| //monfloor.c
double floor(double x)
{
return 3.14;
} |
avec le même test.c
1 2 3 4 5 6 7 8 9 10
| // test.c
#include <stdio.h>
//#include <math.h>
extern double floor(double);
int main () {
printf ("floor 1.1 : %f\n", floor(1.1)) ;
return 0 ;
} |
On compile :
1 2 3 4 5
| ~> gcc -c test.c
~> gcc -c monfloor.c
~> gcc -o test monfloor.o test.o
~> ./test
floor 1.1 : 1.000000 |
N'y aurait-il pas comme un bug de bonne volonté :
je n'ai pas demandé de link avec la libm,
j'ai fourni ma version de floor et pourtant on bypass mes choix et non seulement on écarte mon floor et on me le remplace sans que je demande quoi que ce soit par la version de la libm ????
Ok ... forçons un appel qui ne peut-être optimisé :
monfloor est inchangé, mais test.c devient :
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| // test.c
#include <stdio.h>
//#include <math.h>
extern double floor(double);
int main () {
double d;
printf ("floor 1.1 : %f\n", floor(1.1)) ;
printf ("double value : ");
scanf ("%lf", &d);
printf ("floor(%lf)=%lf\n", d, floor(d));
return 0 ;
} |
Je vire tous les .o et test pour partir sur une compil propre :
1 2 3 4
| ~> rm *.o test
~> gcc -c monfloor.c
~> gcc -c test.c
~> gcc -o test test.o monfloor.o |
Jusque là tout va bien ... testons test :
1 2 3 4
| ~> ./test
floor 1.1 : 1.000000
double value : 10.1
floor(10.100000)=3.140000 |
Ah ???? le premier floor est celui optimisé avec un appel à la libm, le second est le mien ????
Le résultat est identique avec les options -O0 (pas d'optimisation) et -g (debug)
Partager