[resolu(je suis un idiot)]boucle for, sizeof() et warning bizarre

voila dans mon code, j’ai ça en initialisation dans setup() :

for(uint8_t i=0;i<sizeof(T);i++) T[i]=ERREUR;  
  for(uint8_t i=0;i<sizeof(H);i++) H[i]=ERREUR;

avec respectivement T et H deux tableaux de float : float T[4], H[3];

et à la compilation, j’ai ça comme avertissements, que je ne comprends pas :

/home/yann/Arduino/sketchbook/dominicis/dominicis.ino:91:40: warning: iteration 3 invokes undefined behavior [-Waggressive-loop-optimizations]
   for(uint8_t i=0;i<sizeof(H);i++) H[i]=ERREUR;
                                        ^
/home/yann/Arduino/sketchbook/dominicis/dominicis.ino:91:20: note: within this loop
   for(uint8_t i=0;i<sizeof(H);i++) H[i]=ERREUR;
                    ^
/home/yann/Arduino/sketchbook/dominicis/dominicis.ino:90:40: warning: iteration 4 invokes undefined behavior [-Waggressive-loop-optimizations]
   for(uint8_t i=0;i<sizeof(T);i++) T[i]=ERREUR;
                                        ^
/home/yann/Arduino/sketchbook/dominicis/dominicis.ino:90:20: note: within this loop
   for(uint8_t i=0;i<sizeof(T);i++) T[i]=ERREUR;
                    ^

Je démarre mon for avec i=0 et la condition étant i<sizeof(tableau) dans les deux cas, comment ça pourrait merder à la dernière itération ? Je suis pourtant toujours dans le tableau, non ? Ou alors sizeof() ne me donne pas la taille du tableau en partant de 1 ?

Pourtant, de fait à l’exécution j’ai bien un comportement très étrange, ce qui accréditerait la thèse du débordement…

Le code complet est là : GitHub - bricofoy/dominicis

Bonjour,

sizeof donne la taille en octet et non le nombre d'éléments

Si tu veux le nombre d'éléments il faut faire
sizeof H/sizeof H[0]

pffff bordel mais quel boulet......

Bon mais alors comment est-ce possible que le programme fonctionne correctement, sauf dans un cas précis ?
Ça devrait vraiment faire n'importe quoi, du coup

En cas de débordement et d'écriture hors tableau ça peut faire n'importe quoi. Soit ça ne fait pas de problème apparent car la mémoire n'est pas utilisée, soit ça bug, soit le programme crashe complètement suivant ce qu'on écrase en mémoire.

bricofoy:
pffff bordel mais quel boulet......

Bon mais alors comment est-ce possible que le programme fonctionne correctement, sauf dans un cas précis ?
Ça devrait vraiment faire n'importe quoi, du coup

comme essaye de vous le dire le compilateur avec son [color=orange]-Waggressive-loop-optimizations[/color], il essaye de faire une optimization agressive et de dérouler la boucle car il voit que vous parcourez la mémoire pour mettre des valeurs constantes et ce faisant il se rend compte du débordement du tableau.

ensuite tout dépend de ce qu'il y a en mémoire là où ça déborde...

Alors du coup, en utilisant sizeof H/sizeof H[0] :
avant j'avais ça : Le croquis utilise 30310 octets
et maintenant j'ai : Le croquis utilise 30372 octets

La taille d'un float étant de 4, je devrais pas plutôt avoir une itération de moins avec la version corrigée ? et donc un binaire moins gros, et non l'inverse ?

J-M-L:
ensuite tout dépend de ce qu’il y a en mémoire là où ça déborde…

Ben ce qui est curieux, c’est que j’ai constaté deux choses : premièrement, un appel de fonction que ne se fait pas mais seulement de temps en temps, à priori aléatoirement, mais qui se fait normalement si j’ajoute des log sur le port série juste avant et juste après.

et deuxièmement une variable qui prend une valeur bidon, mais pareil si dans le calcul je rajoute du log série, ça remarche…

Bon là du coup ça doit fonctionner

oui c’est le propre du comportement “undefined behavior:slight_smile:

certes

pourtant ça il me le dit à cause de ma ram presque pleine, plutôt. Bon en execution il reste 366o libres, ça devrait aller :slight_smile:

bricofoy:
Alors du coup, en utilisant sizeof H/sizeof H[0] :
avant j'avais ça : Le croquis utilise 30310 octets
et maintenant j'ai : Le croquis utilise 30372 octets

La taille d'un float étant de 4, je devrais pas plutôt avoir une itération de moins avec la version corrigée ? et donc un binaire moins gros, et non l'inverse ?

Et sinon, sur ça, une idée ?

J'ai essayé en mettant les valeurs en dur plutôt que le calcul avec sizeof, ça ne change rien (donc c'est pas ce calcul qui fait grossir le binaire)

bricofoy:
pourtant ça il me le dit à cause de ma ram presque pleine, plutôt.

Non non il a bien dit ça à propos de la boucle :slight_smile:

[color=orange]dominicis.ino:90:40: warning: iteration 4 [b][color=red]invokes undefined behavior[/color][/b] [-Waggressive-loop-optimizations][/color]

Ha oui pardon :stuck_out_tongue: Pfff ça va pas moi ce soir... Sinon sur l'autre question, une idée ? C'est pas vital mais ça m'interroge

La taille d'un float étant de 4, je devrais pas plutôt avoir une itération de moins avec la version corrigée ? et donc un binaire moins gros, et non l'inverse ?

ce sont des variables globales ? une itération de plus ou de moins ne change rien à la taille du code puisque c'est une itération :slight_smile: (sauf quand l'optimiser la "déroule")

Oui les deux tableaux sont des variables globales. Bien vu pour l’itération, mais du coup je pige encore moins, la taille n’aurait pas du changer, et même si ça l’avait “déroulé” elle aurait du réduire…

bricofoy:
Oui les deux tableaux sont des variables globales. Bien vu pour l’itération, mais du coup je pige encore moins

si vous faites for (byte i = 0; i < 3; i++) tableau[i] = constante;l’optimiseur peut décider de transformer cela en

tableau[0] = constante;
tableau[1] = constante;
tableau[2] = constante;

il va optimiser pour la performance plutôt que pour la place en flash (bien que quand il y en a peu, ça doit même être plus compact comme cela)

il se peut que quand vous aviez le bug il choisissait de ne pas faire le déroulé et que maintenant il le fasse… faudrait regarder l’assembleur

Merci

J-M-L:
il va optimiser pour la performance plutôt que pour la place en flash (bien que quand il y en a peu, ça doit même être plus compact comme cela)

Mais alors existe il une directive à ajouter pour interdire localement de dérouler le code, sans changer la configuration ? Un #pragma quelque-chose ?

Pas à ma connaissance mais un hack du genre intégrer un

__asm__ __volatile__("")

dans la boucle va sans doute l’empêcher de le faire ou alors rendre l’indice de boucle volatile mais la çà rajoute du code

Un autre hack est d’appeler une fonction externe que le compilo ne connaît pas encore et mettre une fonction vide. Ça sera viré plus tard sans doute

Édit: il y a aussi cela à lire

Alors je viens de faire quelques essais :

  for(uint8_t i=0;i<(sizeof(T)/sizeof(T[0]));i++) {__asm__ __volatile__(""); T[i]=ERREUR; } 
  for(uint8_t i=0;i<(sizeof(H)/sizeof(H[0]));i++) {__asm__ __volatile__(""); H[i]=ERREUR; }

ne change absolument rien : Le croquis utilise 30372 octets

Mais en revanche, au vu de ce qui se passe dans ce post

  for(uint8_t i=0;i<(sizeof(T)/sizeof(T[0]));i++) {__asm__ __volatile__("nop"); T[i]=ERREUR; } 
  for(uint8_t i=0;i<(sizeof(H)/sizeof(H[0]));i++) {__asm__ __volatile__("nop"); H[i]=ERREUR; }

donne : Le croquis utilise 30336 octets

C’est quand même très inquiétant que le compilateur puisse réorganiser voire virer (voir l’autre post) des portions du code sans qu’il y ait de moyen de le bloquer…

Vous pouvez le bloquer en supprimant l’optimisation de code lors de la compilation.

Dans la majorité des cas l’optimisation fait ce qu’il faut