Je me suis remis au C et je m'amuse donc avec des petits prgs.
Le dernier en date m'a fait découvrir un truc bizarre lorsque je compile
avec l'option O2.
Je suis sous Slackware 14.0 avec gcc 4.7.1.
Voilà le source de mon prg (fibo.c) qui permet d'afficher les 1ers nbs
de Fibo :
-------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
int main(void)
{
long long a = 0, b = 1, tempo;
int i;
for (i = 0; i < MAX && a >= 0; i++) {
printf("%i %lld %i\n", i , a, a >= 0);
tempo = b;
b += a;
a = tempo;
/*
* en 2 instructions
* b += a;
* a = b - a;
*/
}
printf("----------\n%lld %i\n", a, a >= 0);
return EXIT_SUCCESS;
}
-------------------------------------------
Donc rien de bien compliqué.
gcc fibo.c && ./a.out donne à la fin :
...
91 4660046610375530309 1
92 7540113804746346429 1
----------
-6246583658587674878 0
Ce qui est bien ce que j'attends.
Avec les options -O ou -O1, j'obtiens la même chose.
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Cyprien Nicolas
Le 04/08/2013 08:44, Nicolas BERNE écrivit :
Ca ne vient pas du type long long, car j'ai fait des essais avec des int ou des long et j'obtiens les mêmes résultats bizarres avec l'option -O2.
Si quelqu'un pouvait éclairer ma lanterne...
Je pense que le compilo voit que tu ne fais que des additions sur la variable a, donc il considère que a >= 0LL est toujours vrai et optimise ce test.
gcc -O2 -fno-strict-overflow fibo.c et ça marche comme tu l'attends.
-fstrict-overflow permet au compilo de ne pas se poser de question sur l'overflow, le programmeur sait ce qu'il fait, et donc il estime que ça ne peut pas arriver. Du coup a ne peut jamais devenir négatif si cette option est activée (parce que a est un nombre signé). Voir le man de gcc pour plus de détails.
Si tu remplaces ta déclaration de a par:
unsigned long long a = 0;
Alors même avec -O0, ton programme va jusqu'à cent.
L'option -fwrapv peut jouer aussi.
-- « Ceci n'est pas une signature. » — René Magritte (Apocryphe)
Le 04/08/2013 08:44, Nicolas BERNE écrivit :
Ca ne vient pas du type long long, car j'ai fait des essais avec des int
ou des long et j'obtiens les mêmes résultats bizarres avec l'option -O2.
Si quelqu'un pouvait éclairer ma lanterne...
Je pense que le compilo voit que tu ne fais que des additions sur la
variable a, donc il considère que a >= 0LL est toujours vrai et optimise
ce test.
gcc -O2 -fno-strict-overflow fibo.c et ça marche comme tu l'attends.
-fstrict-overflow permet au compilo de ne pas se poser de question sur
l'overflow, le programmeur sait ce qu'il fait, et donc il estime que ça
ne peut pas arriver. Du coup a ne peut jamais devenir négatif si cette
option est activée (parce que a est un nombre signé).
Voir le man de gcc pour plus de détails.
Si tu remplaces ta déclaration de a par:
unsigned long long a = 0;
Alors même avec -O0, ton programme va jusqu'à cent.
L'option -fwrapv peut jouer aussi.
--
« Ceci n'est pas une signature. » — René Magritte (Apocryphe)
Ca ne vient pas du type long long, car j'ai fait des essais avec des int ou des long et j'obtiens les mêmes résultats bizarres avec l'option -O2.
Si quelqu'un pouvait éclairer ma lanterne...
Je pense que le compilo voit que tu ne fais que des additions sur la variable a, donc il considère que a >= 0LL est toujours vrai et optimise ce test.
gcc -O2 -fno-strict-overflow fibo.c et ça marche comme tu l'attends.
-fstrict-overflow permet au compilo de ne pas se poser de question sur l'overflow, le programmeur sait ce qu'il fait, et donc il estime que ça ne peut pas arriver. Du coup a ne peut jamais devenir négatif si cette option est activée (parce que a est un nombre signé). Voir le man de gcc pour plus de détails.
Si tu remplaces ta déclaration de a par:
unsigned long long a = 0;
Alors même avec -O0, ton programme va jusqu'à cent.
L'option -fwrapv peut jouer aussi.
-- « Ceci n'est pas une signature. » — René Magritte (Apocryphe)
Nicolas BERNE
Thus Spoke Cyprien Nicolas :
Le 04/08/2013 08:44, Nicolas BERNE écrivit : > Ca ne vient pas du type long long, car j'ai fait des essais avec des int > ou des long et j'obtiens les mêmes résultats bizarres avec l'option -O2. > > Si quelqu'un pouvait éclairer ma lanterne...
Je pense que le compilo voit que tu ne fais que des additions sur la variable a, donc il considère que a >= 0LL est toujours vrai et optimise ce test.
Un peu rude comme optimisation...
gcc -O2 -fno-strict-overflow fibo.c et ça marche comme tu l'attends.
-fstrict-overflow permet au compilo de ne pas se poser de question sur l'overflow, le programmeur sait ce qu'il fait, et donc il estime que ça ne peut pas arriver. Du coup a ne peut jamais devenir négatif si cette option est activée (parce que a est un nombre signé). Voir le man de gcc pour plus de détails.
Si tu remplaces ta déclaration de a par:
unsigned long long a = 0;
Alors même avec -O0, ton programme va jusqu'à cent.
L'option -fwrapv peut jouer aussi.
Merci pour les explications.
A+
-- I like my coffee black Just like my Metal
Thus Spoke Cyprien Nicolas <cyp-nospam@fulax.fr>:
Le 04/08/2013 08:44, Nicolas BERNE écrivit :
> Ca ne vient pas du type long long, car j'ai fait des essais avec des int
> ou des long et j'obtiens les mêmes résultats bizarres avec l'option -O2.
>
> Si quelqu'un pouvait éclairer ma lanterne...
Je pense que le compilo voit que tu ne fais que des additions sur la
variable a, donc il considère que a >= 0LL est toujours vrai et optimise
ce test.
Un peu rude comme optimisation...
gcc -O2 -fno-strict-overflow fibo.c et ça marche comme tu l'attends.
-fstrict-overflow permet au compilo de ne pas se poser de question sur
l'overflow, le programmeur sait ce qu'il fait, et donc il estime que ça
ne peut pas arriver. Du coup a ne peut jamais devenir négatif si cette
option est activée (parce que a est un nombre signé).
Voir le man de gcc pour plus de détails.
Si tu remplaces ta déclaration de a par:
unsigned long long a = 0;
Alors même avec -O0, ton programme va jusqu'à cent.
Le 04/08/2013 08:44, Nicolas BERNE écrivit : > Ca ne vient pas du type long long, car j'ai fait des essais avec des int > ou des long et j'obtiens les mêmes résultats bizarres avec l'option -O2. > > Si quelqu'un pouvait éclairer ma lanterne...
Je pense que le compilo voit que tu ne fais que des additions sur la variable a, donc il considère que a >= 0LL est toujours vrai et optimise ce test.
Un peu rude comme optimisation...
gcc -O2 -fno-strict-overflow fibo.c et ça marche comme tu l'attends.
-fstrict-overflow permet au compilo de ne pas se poser de question sur l'overflow, le programmeur sait ce qu'il fait, et donc il estime que ça ne peut pas arriver. Du coup a ne peut jamais devenir négatif si cette option est activée (parce que a est un nombre signé). Voir le man de gcc pour plus de détails.
Si tu remplaces ta déclaration de a par:
unsigned long long a = 0;
Alors même avec -O0, ton programme va jusqu'à cent.
L'option -fwrapv peut jouer aussi.
Merci pour les explications.
A+
-- I like my coffee black Just like my Metal
Samuel DEVULDER
Le 04/08/2013 11:05, Nicolas BERNE a écrit :
Thus Spoke Cyprien Nicolas :
Je pense que le compilo voit que tu ne fais que des additions sur la variable a, donc il considère que a >= 0LL est toujours vrai et optimise ce test.
Oui c'est exactement cela.
Un peu rude comme optimisation...
Bah: je crois que la norme dit que le comportement est indéfini en cas d'overflow sur des valeurs signées. En gros le compilo peut faire ce qu'il veut ce sera toujours "en norme".
(...)
unsigned long long a = 0;
Alors même avec -O0, ton programme va jusqu'à cent.
La norme décrit en revanche les overflow des unsigned, et il n'y a pas d'undefined behavior avec eux.
sam.
Le 04/08/2013 11:05, Nicolas BERNE a écrit :
Thus Spoke Cyprien Nicolas <cyp-nospam@fulax.fr>:
Je pense que le compilo voit que tu ne fais que des additions sur la
variable a, donc il considère que a >= 0LL est toujours vrai et optimise
ce test.
Oui c'est exactement cela.
Un peu rude comme optimisation...
Bah: je crois que la norme dit que le comportement est indéfini en cas
d'overflow sur des valeurs signées. En gros le compilo peut faire ce
qu'il veut ce sera toujours "en norme".
(...)
unsigned long long a = 0;
Alors même avec -O0, ton programme va jusqu'à cent.
La norme décrit en revanche les overflow des unsigned, et il n'y a pas
d'undefined behavior avec eux.
Je pense que le compilo voit que tu ne fais que des additions sur la variable a, donc il considère que a >= 0LL est toujours vrai et optimise ce test.
Oui c'est exactement cela.
Un peu rude comme optimisation...
Bah: je crois que la norme dit que le comportement est indéfini en cas d'overflow sur des valeurs signées. En gros le compilo peut faire ce qu'il veut ce sera toujours "en norme".
(...)
unsigned long long a = 0;
Alors même avec -O0, ton programme va jusqu'à cent.
La norme décrit en revanche les overflow des unsigned, et il n'y a pas d'undefined behavior avec eux.
sam.
Nicolas BERNE
Thus Spoke Samuel DEVULDER :
Le 04/08/2013 11:05, Nicolas BERNE a écrit :
> Thus Spoke Cyprien Nicolas : >> Je pense que le compilo voit que tu ne fais que des additions sur la >> variable a, donc il considère que a >= 0LL est toujours vrai et optimise >> ce test.
Oui c'est exactement cela.
> Un peu rude comme optimisation...
Bah: je crois que la norme dit que le comportement est indéfini en cas d'overflow sur des valeurs signées. En gros le compilo peut faire ce qu'il veut ce sera toujours "en norme".
J'ai essayé de feinter le compilo ainsi :
int f(int x) { return ((x+1)*(x+2)); }
dans main : int x;
srand(time(NULL));
x = rand()%2 - 2; // x vaut donc -2 ou -1 a = f(x); // a vaut toujours 0
Et là où ça devient vraiment bizarre, si j'enlève le test a >= 0 dans la boucle for, j'obtiens bien le résultat attendu avec -O2
Thus Spoke Samuel DEVULDER <samuel-dot-devulder@laposte-dot-com>:
Le 04/08/2013 11:05, Nicolas BERNE a écrit :
> Thus Spoke Cyprien Nicolas <cyp-nospam@fulax.fr>:
>> Je pense que le compilo voit que tu ne fais que des additions sur la
>> variable a, donc il considère que a >= 0LL est toujours vrai et optimise
>> ce test.
Oui c'est exactement cela.
> Un peu rude comme optimisation...
Bah: je crois que la norme dit que le comportement est indéfini en cas
d'overflow sur des valeurs signées. En gros le compilo peut faire ce
qu'il veut ce sera toujours "en norme".
J'ai essayé de feinter le compilo ainsi :
int f(int x) {
return ((x+1)*(x+2));
}
dans main :
int x;
srand(time(NULL));
x = rand()%2 - 2; // x vaut donc -2 ou -1
a = f(x); // a vaut toujours 0
Et là où ça devient vraiment bizarre, si j'enlève le test a >= 0 dans la
boucle for, j'obtiens bien le résultat attendu avec -O2
> Thus Spoke Cyprien Nicolas : >> Je pense que le compilo voit que tu ne fais que des additions sur la >> variable a, donc il considère que a >= 0LL est toujours vrai et optimise >> ce test.
Oui c'est exactement cela.
> Un peu rude comme optimisation...
Bah: je crois que la norme dit que le comportement est indéfini en cas d'overflow sur des valeurs signées. En gros le compilo peut faire ce qu'il veut ce sera toujours "en norme".
J'ai essayé de feinter le compilo ainsi :
int f(int x) { return ((x+1)*(x+2)); }
dans main : int x;
srand(time(NULL));
x = rand()%2 - 2; // x vaut donc -2 ou -1 a = f(x); // a vaut toujours 0
Et là où ça devient vraiment bizarre, si j'enlève le test a >= 0 dans la boucle for, j'obtiens bien le résultat attendu avec -O2
Regarde le code ASM généré. Je ne serais pas surpris que le compilo ait transformé: for (i = 0; i < MAX && a >= 0; i++) {... (a>=0) ...}
en
i = 0; if(a>=0) do { ... (a>=0) ... } while(++i<MAX && a>=0);
Or comme ce qu'il se passe dans "..." n'influence pas la valeur de "a>=0", le compilo effectue:
i = 0; if(a>=0) do { ... (1) ... /* d'où le printf à 1 */ } while(++i<MAX && 1);
Ca me semble très simple finalement.
sam.
Nicolas BERNE
Thus Spoke Samuel DEVULDER :
Le 05/08/2013 07:28, Nicolas BERNE a écrit :
> Bref, moi ça me dépasse.
Regarde le code ASM généré. Je ne serais pas surpris que le compilo ait transformé:
Heu, l'ASM et moi...
for (i = 0; i < MAX && a >= 0; i++) {... (a>=0) ...}
en
i = 0; if(a>=0) do { ... (a>=0) ... } while(++i<MAX && a>=0);
Or comme ce qu'il se passe dans "..." n'influence pas la valeur de "a>=0", le compilo effectue:
Justement, comment diable le compilo a pu décidé que a est toujours positif, vu la façon dont j'initialise a à 0 (ça m'étonnerait que le compilo ait pu analyser que, malgrè le rand, a vaut toujours 0 au départ).
i = 0; if(a>=0) do { ... (1) ... /* d'où le printf à 1 */ } while(++i<MAX && 1);
Ca me semble très simple finalement.
Mais pourquoi le compilo décide de remplacer a>=0 par 1 lorsque ce test est dans le for (ou le while) et ne le fait pas dans le cas contraire.
D'après ce que tu as écrit, le cas où le test n'est pas dans le for devient : i = 0; do { ... (a>=0) ... } while(++i<MAX); Et là, apparemment, il ne remplace plus le test par 1...
Enfin, encore un mystère, j'ai remplacé && par & et ça donne le résultat attendu.
Par contre, si j'initialise explicitement a à 0, que ce soit & ou &&, le test a>=0 est toujours remplacé par 1.
A+
-- I like my coffee black Just like my Metal
Thus Spoke Samuel DEVULDER <samuel-dot-devulder@laposte-dot-com>:
Le 05/08/2013 07:28, Nicolas BERNE a écrit :
> Bref, moi ça me dépasse.
Regarde le code ASM généré. Je ne serais pas surpris que le compilo ait
transformé:
Heu, l'ASM et moi...
for (i = 0; i < MAX && a >= 0; i++) {... (a>=0) ...}
en
i = 0; if(a>=0) do {
... (a>=0) ...
} while(++i<MAX && a>=0);
Or comme ce qu'il se passe dans "..." n'influence pas la valeur de
"a>=0", le compilo effectue:
Justement, comment diable le compilo a pu décidé que a est toujours
positif, vu la façon dont j'initialise a à 0 (ça m'étonnerait que le
compilo ait pu analyser que, malgrè le rand, a vaut toujours 0 au départ).
i = 0; if(a>=0) do {
... (1) ... /* d'où le printf à 1 */
} while(++i<MAX && 1);
Ca me semble très simple finalement.
Mais pourquoi le compilo décide de remplacer a>=0 par 1 lorsque ce test
est dans le for (ou le while) et ne le fait pas dans le cas contraire.
D'après ce que tu as écrit, le cas où le test n'est pas dans le for
devient :
i = 0; do {
... (a>=0) ...
} while(++i<MAX);
Et là, apparemment, il ne remplace plus le test par 1...
Enfin, encore un mystère, j'ai remplacé && par & et ça donne le
résultat attendu.
Par contre, si j'initialise explicitement a à 0, que ce soit & ou &&, le
test a>=0 est toujours remplacé par 1.
Regarde le code ASM généré. Je ne serais pas surpris que le compilo ait transformé:
Heu, l'ASM et moi...
for (i = 0; i < MAX && a >= 0; i++) {... (a>=0) ...}
en
i = 0; if(a>=0) do { ... (a>=0) ... } while(++i<MAX && a>=0);
Or comme ce qu'il se passe dans "..." n'influence pas la valeur de "a>=0", le compilo effectue:
Justement, comment diable le compilo a pu décidé que a est toujours positif, vu la façon dont j'initialise a à 0 (ça m'étonnerait que le compilo ait pu analyser que, malgrè le rand, a vaut toujours 0 au départ).
i = 0; if(a>=0) do { ... (1) ... /* d'où le printf à 1 */ } while(++i<MAX && 1);
Ca me semble très simple finalement.
Mais pourquoi le compilo décide de remplacer a>=0 par 1 lorsque ce test est dans le for (ou le while) et ne le fait pas dans le cas contraire.
D'après ce que tu as écrit, le cas où le test n'est pas dans le for devient : i = 0; do { ... (a>=0) ... } while(++i<MAX); Et là, apparemment, il ne remplace plus le test par 1...
Enfin, encore un mystère, j'ai remplacé && par & et ça donne le résultat attendu.
Par contre, si j'initialise explicitement a à 0, que ce soit & ou &&, le test a>=0 est toujours remplacé par 1.
A+
-- I like my coffee black Just like my Metal
espie
le plus simple, et portable, serait: - de jouer avec des unsigned long long - de garder la valeur precedente. - de t'arreter des que ca deborde, ce qui est tres simple (suffit de verifier que la nouvelle valeur calculee est plus petite que l'ancienne)...
le plus simple, et portable, serait:
- de jouer avec des unsigned long long
- de garder la valeur precedente.
- de t'arreter des que ca deborde, ce qui est tres simple (suffit de verifier
que la nouvelle valeur calculee est plus petite que l'ancienne)...
le plus simple, et portable, serait: - de jouer avec des unsigned long long - de garder la valeur precedente. - de t'arreter des que ca deborde, ce qui est tres simple (suffit de verifier que la nouvelle valeur calculee est plus petite que l'ancienne)...
Nicolas BERNE
Thus Spoke Marc Espie :
le plus simple, et portable, serait: - de jouer avec des unsigned long long - de garder la valeur precedente. - de t'arreter des que ca deborde, ce qui est tres simple (suffit de verifier que la nouvelle valeur calculee est plus petite que l'ancienne)...
Salut,
Effectivement, comme ça, plus de soucis avec -O2. Merci.
int main(void) { unsigned long long int a = 0, b = 1, tempo; int i = 0;
for (i = 0; i < MAX && b >= a; i++) { printf("%i %llu %llu %in", i , a, b, b >= a); tempo = b; b += a; a = tempo; } printf("----------n%llu %llu %in", a, b, b >= a);
le plus simple, et portable, serait:
- de jouer avec des unsigned long long
- de garder la valeur precedente.
- de t'arreter des que ca deborde, ce qui est tres simple (suffit de verifier
que la nouvelle valeur calculee est plus petite que l'ancienne)...
Salut,
Effectivement, comme ça, plus de soucis avec -O2.
Merci.
int main(void) {
unsigned long long int a = 0, b = 1, tempo;
int i = 0;
for (i = 0; i < MAX && b >= a; i++) {
printf("%i %llu %llu %in", i , a, b, b >= a);
tempo = b;
b += a;
a = tempo;
}
printf("----------n%llu %llu %in", a, b, b >= a);
le plus simple, et portable, serait: - de jouer avec des unsigned long long - de garder la valeur precedente. - de t'arreter des que ca deborde, ce qui est tres simple (suffit de verifier que la nouvelle valeur calculee est plus petite que l'ancienne)...
Salut,
Effectivement, comme ça, plus de soucis avec -O2. Merci.
int main(void) { unsigned long long int a = 0, b = 1, tempo; int i = 0;
for (i = 0; i < MAX && b >= a; i++) { printf("%i %llu %llu %in", i , a, b, b >= a); tempo = b; b += a; a = tempo; } printf("----------n%llu %llu %in", a, b, b >= a);
D'après ce que tu as écrit, le cas où le test n'est pas dans le for devient : i = 0; do { ... (a>=0) ... } while(++i<MAX); Et là, apparemment, il ne remplace plus le test par 1...
Parce qu'il ne peut pas inférer que a>=0. Il y a simplement trop peu d'information (elle a disparu du test du wile). Cette inférence vient de la simple règle que lors du bouclage du while avec a>=0 en condition, on entre dans la boucle avec, bien entendu, a>=0 du coup il ne ré-évalue plus cette condition et la remplace directement par 1.
sam.
Le 05/08/2013 09:51, Nicolas BERNE a écrit :
D'après ce que tu as écrit, le cas où le test n'est pas dans le for
devient :
i = 0; do {
... (a>=0) ...
} while(++i<MAX);
Et là, apparemment, il ne remplace plus le test par 1...
Parce qu'il ne peut pas inférer que a>=0. Il y a simplement trop peu
d'information (elle a disparu du test du wile). Cette inférence vient de
la simple règle que lors du bouclage du while avec a>=0 en condition, on
entre dans la boucle avec, bien entendu, a>=0 du coup il ne ré-évalue
plus cette condition et la remplace directement par 1.
D'après ce que tu as écrit, le cas où le test n'est pas dans le for devient : i = 0; do { ... (a>=0) ... } while(++i<MAX); Et là, apparemment, il ne remplace plus le test par 1...
Parce qu'il ne peut pas inférer que a>=0. Il y a simplement trop peu d'information (elle a disparu du test du wile). Cette inférence vient de la simple règle que lors du bouclage du while avec a>=0 en condition, on entre dans la boucle avec, bien entendu, a>=0 du coup il ne ré-évalue plus cette condition et la remplace directement par 1.
sam.
Antoine Leca
Nicolas BERNE écrivit :
Thus Spoke Cyprien Nicolas :
Le 04/08/2013 08:44, Nicolas BERNE écrivit :
Ca ne vient pas du type long long, car j'ai fait des essais avec des int ou des long et j'obtiens les mêmes résultats bizarres avec l'option -O2.
Si quelqu'un pouvait éclairer ma lanterne...
Je pense que le compilo voit que tu ne fais que des additions sur la variable a, donc il considère que a >= 0LL est toujours vrai et optimise ce test.
Un peu rude comme optimisation...
Non. Il faut que tu te rendes compte que ton code est *faux* : il utilise une hypothèse (ici que le compilateur va utiliser un système d'entiers «qui boucle», autrement dit l'entier suivant INT_MAX est INT_MIN) qui est peut être intuitive pour toi, mais n'est *pas* garanti par la norme et en fait pour laquelle il existe des implémentations (genre entiers saturés : INT_MAX+1==INT_MAX) qui n'ont pas ce comportement.
Ce qui se passe, c'est que pour optimiser, le compilateur est parfois amené à faire des hypothèses de nécessité sur le comportement attendu du code ; et plus on cherche à optimiser, plus il deveinet nécessaire de faire de telles hypothèses. Si le code respecte la norme, il n'y aura pas de problème, les hypothèses seront valides et le code optimisé ira plus vite ; par contre, si comme c'est le cas ici, le code enfreint les règles, cela dérape.
Antoine
Nicolas BERNE écrivit :
Thus Spoke Cyprien Nicolas <cyp-nospam@fulax.fr>:
Le 04/08/2013 08:44, Nicolas BERNE écrivit :
Ca ne vient pas du type long long, car j'ai fait des essais avec des int
ou des long et j'obtiens les mêmes résultats bizarres avec l'option -O2.
Si quelqu'un pouvait éclairer ma lanterne...
Je pense que le compilo voit que tu ne fais que des additions sur la
variable a, donc il considère que a >= 0LL est toujours vrai et optimise
ce test.
Un peu rude comme optimisation...
Non.
Il faut que tu te rendes compte que ton code est *faux* : il utilise une
hypothèse (ici que le compilateur va utiliser un système d'entiers «qui
boucle», autrement dit l'entier suivant INT_MAX est INT_MIN) qui est
peut être intuitive pour toi, mais n'est *pas* garanti par la norme et
en fait pour laquelle il existe des implémentations (genre entiers
saturés : INT_MAX+1==INT_MAX) qui n'ont pas ce comportement.
Ce qui se passe, c'est que pour optimiser, le compilateur est parfois
amené à faire des hypothèses de nécessité sur le comportement attendu du
code ; et plus on cherche à optimiser, plus il deveinet nécessaire de
faire de telles hypothèses. Si le code respecte la norme, il n'y aura
pas de problème, les hypothèses seront valides et le code optimisé ira
plus vite ; par contre, si comme c'est le cas ici, le code enfreint les
règles, cela dérape.
Ca ne vient pas du type long long, car j'ai fait des essais avec des int ou des long et j'obtiens les mêmes résultats bizarres avec l'option -O2.
Si quelqu'un pouvait éclairer ma lanterne...
Je pense que le compilo voit que tu ne fais que des additions sur la variable a, donc il considère que a >= 0LL est toujours vrai et optimise ce test.
Un peu rude comme optimisation...
Non. Il faut que tu te rendes compte que ton code est *faux* : il utilise une hypothèse (ici que le compilateur va utiliser un système d'entiers «qui boucle», autrement dit l'entier suivant INT_MAX est INT_MIN) qui est peut être intuitive pour toi, mais n'est *pas* garanti par la norme et en fait pour laquelle il existe des implémentations (genre entiers saturés : INT_MAX+1==INT_MAX) qui n'ont pas ce comportement.
Ce qui se passe, c'est que pour optimiser, le compilateur est parfois amené à faire des hypothèses de nécessité sur le comportement attendu du code ; et plus on cherche à optimiser, plus il deveinet nécessaire de faire de telles hypothèses. Si le code respecte la norme, il n'y aura pas de problème, les hypothèses seront valides et le code optimisé ira plus vite ; par contre, si comme c'est le cas ici, le code enfreint les règles, cela dérape.