Chaque fois que vous écrivez une équation en C / C ++, les types de données utilisés ont un effet très réel sur la sortie de l'équation.
Chaque type, comme int
, float
et unsigned long
ont des comportements différents, et prennent une certaine quantité d'espace en mémoire pour stocker.
int
(sur arduino) est stocké sur 16 bits, la moitié de ses valeurs étant données à des nombres négatifs, la moitié 1 à des valeurs positives et une valeur à 0. Cela lui donne une plage de -2 ^ 15 (-32 768) à + 2 ^ 15-1 (32 767).
unsigned long
(sur arduino) est de 32 bits, mais aucun n'est désigné comme négatif. sa plage est alors de 0 à 2 ^ 32-1 (4294967295).
Quel genre de mathématiques? Quel autre type de traitement est exclu lorsque vous travaillez avec des millis?
Le nœud du problème est que le temps que les millis reviennent a dépassé 32767 et que vous avez essayé de le stocker dans un int, l'arduino n'a pas pu le faire, car un int
ne peut pas contenir un si grand nombre. Le type de calcul hors limites est le calcul mathématique qui s'applique aux types de données plus petits, et non à des opérations spécifiques. Peut-être que ces exemples aideront:
int i = 32767;
Serial.println(i);
//No problems here; it fits just fine
32767
i = 32767 + 1;
Serial.println(i);
//Oh no, the value didn't fit
-32768
unsigned long fake_millis = 42000;
i = fake_millis;
Serial.println(i);
//This is an example of millis going past an int
-23536
i = -10;
unsigned int j = i;
Serial.println(j);
//no way to put a negative number in an unsigned value
65526
uint32_t k = fake_millis;
Serial.println(k);
//unsigned long is a uint32_t on arduino; this works great!
42000
La façon dont cela est mis en œuvre est vraiment très géniale; Si vous souhaitez savoir d'où viennent ces nombres et pourquoi ils se répercutent dans la façon dont ils le font, vous devriez examiner les mêmes explications des représentations des nombres du complément à deux.
unsigned long
peut changer avec différentes plates-formes (par exemple x86),uint32_t
sera toujours 32 bits non signés partout.32767 + 1
) donne un comportement non défini, ce qui est presque toujours une mauvaise chose . Vos autres exemples sont des comportements documentés sur lesquels vous pouvez compter.millis()
renvoie ununsigned long
, qui est un entier non signé 32 bits sur l'Arduino. Lorsque vous essayez ensuite de faire quelque chose commeunsigned int time = millis() - 1000
, vous essayez de stocker cela dans un entier non signé 16 bitsunsigned int
. Un entier 16 bits ne peut jamais contenir une valeur 32 bits.Selon la spécification C , paragraphe 6.3.1.3, les 16 bits supérieurs sont rejetés.
Si possible, conservez la
millis()
sortie dans ununsigned long
et utilisez uniquement les types de données avec moins de bits lorsque vous êtes absolument sûr de ne pas perdre de bits.Il y a plus d'informations sur les conversions explicites en C ici: https://stackoverflow.com/a/13652624/1544337
la source
uint32_t
qui se trouve être ununsigned long
arduino?unsigned long
.int time = millis() - 1000
), le résultat est similaire: les 16 bits supérieurs sont rejetés. Cette fois, la norme C indique que le résultat est défini par l'implémentation et que le comportement est spécifié dans la documentation gcc sur le comportement des entiers défini par l'implémentation (quatrième puce).Lorsque vous voulez faire des choses avec millis (), n'oubliez pas d'initialiser votre variable avec le type "uint32_t"
Faites donc quelque chose comme "uint32_t last_millis" où vous stockerez la sortie de la fonction "millis ()".
Sinon, comme les autres l'ont dit, cela déborderait au-delà de 31 000, ce qui se produira assez rapidement.
la source