Ram+Seriale+Overflow

Sarebbero da disassemblare i 2 firmware creati ma mi pare una cosa un po' pacco per un problema così banale, si mette unsigned long e siamo tutti felici :wink:

lesto:
leo ha testato questo con successo, quindi il casting avviene, bisognerebbe capire se esistono casi particolari

Non è vero che funziona, o meglio ti funziona su Arduino che non ti fa vedere le warning, se provi a compilare una cosa simile con AvrStudio ottieni subito una bella warning sul cast e una sulla if stessa, viene compilato lo stesso, ma è una forzatura e lo fai a tuo rischio e pericolo, ovvero poi non lamentarti se il programma fa cose strane :slight_smile:

legacy:
siete tutti bocciati per il semplice fatto che nell'embedded i cast NON si devono MAI fare!

In embedded il cast si usa eccome, anzi è uno degli strumenti messi a disposizione dal C e non c'è alcun motivo per non usarlo.
Ovviamente tocca ricordarsi di accendere il cervello quando si utilizza il cast perché è facile creare casini immensi se usato male, ma la stessa cosa si applica a maggior ragione ai puntatori, alle strutture/unioni etc.

legacy:
mega rofl, adesso il Misra e' inutile perche' lo dice astro.

Dove direbbero le regole del MISRA C che non si deve usare il casting ? A me risulta che dicono come e quando deve essere impiegato il cast e quando non deve essere impiegato e che deve essere sempre esplicito, ovvero non usare mai il cast implicito dei compilatori che è una cosa ben diversa dal non usarlo in assoluto.

ci mancava il troll di turno, ma questo e' sempre il solito ?
devo segnalarlo ai moderatori :slight_smile:

tornando alla questione mi fa piacere che con un mio semplice esempio abbia montato tutta sta storia, quindi una domanda secca

  • visto che non e' che vi seguo molto, nel senso che l'argomento e' per me difficile, usare nel mio esempio due unsigned long, sia per Time che per ScrollTime, evita problemi ? nel senso che l'overflow che comunque avverra' piu' in la nel tempo, non mi blocchera' lo scroll del display ?

il mio dubbio deriva da questo, cosi' come la INT diventa magicamente negativa e poi il cast fa casino, perche' non dovrebbe avvenire anche quando la unsigned long diventa negativa, il cast la inverte ecc ecc ?

non e' che si sposta solo il problema piu' avanti ?

legacy:

Testato:
ci mancava il troll di turno, ma questo e' sempre il solito ?
devo segnalarlo ai moderatori :slight_smile:

ho segnalato il tuo intervento molesto ed offensivo, oltre al fatto che e' detto a sproposito perche' ci sono tutta una serie di ragioni che non cito dietro all'intervento di prima, pero' tu mi hai confermato che ho fatto bene a cancellarlo segno che ho valutato per me non interessante ulteriori discussioni.

quote cautelativo:)

Testato:
il mio dubbio deriva da questo, cosi' come la INT diventa magicamente negativa e poi il cast fa casino, perche' non dovrebbe avvenire anche quando la unsigned long diventa negativa, il cast la inverte ecc ecc ?

non e' che si sposta solo il problema piu' avanti ?

"unsigned" vuol dire proprio SENZA segno, come può diventare negativa?!

il dubbio mi viene perche' leo dice:

leo72:
Usando l'unsigned int con il codice di Testato va in blocco dopo un po'

quindi credo sia lecito chiedersi chi mi tutela con unsigned long ?
infatti ho provato anche io, ed entrambi si bloccano,
con INT si blocca dopo una 30ina di secondi, e con UNSIGNED INT dopo 1 minuto.

se con unsigned long non si blocca vuol dire che c'e' un bug solo su int ed unsigned int ?

Testato:
...
Usando l'unsigned int con il codice di Testato va in blocco dopo un po'
...

Questo effetto é logico perché un Unsigned int ha la possibilitá di memorizzare un numero positivo quasi 2 volte piú grande di un int. (16 bit contro 15 bit).
Ciai Uwe

uwefed:

Testato:
...
Usando l'unsigned int con il codice di Testato va in blocco dopo un po'
...

Questo effetto é logico perché un Unsigned int ha la possibilitá di memorizzare un numero positivo quasi 2 volte piú grande di un int. (16 bit contro 15 bit).
Ciai Uwe

Appunto.

appunto, ma non e' questo il punto :slight_smile:

mi sembra che lesto dica che gli Unsigned, non avendo segno, dovrebbero regolarmente andare in overflow, e ripartire da zero, cosa che io mi aspettavo, invece non lo fa.
si incarta sia con int che con unsigned int, perche' con unsigned long non si blocca ?

Sia unsigned int che unsigned long vanno in overflow, se si comportano allo stesso modo dovrebbero :

  • O funzionare entrambi, semplicemente andado in overflow in momenti diversi e ripartendo da zero
  • Oppure bloccarsi entrambi nel momento dell'overflow, che capitera' in momenti diversi

l'attuale situazione invece e' che Unsigned Int blocca il codice all'overfow, Unsigned Long non lo blocca mai, nemmeno dopo l'overflow

Testato:
appunto, ma non e' questo il punto :slight_smile:

mi sembra che lesto dica che gli Unsigned, non avendo segno, dovrebbero regolarmente andare in overflow, e ripartire da zero, cosa che io mi aspettavo, invece non lo fa.
si incarta sia con int che con unsigned int, perche' con unsigned long non si blocca ?

Sia unsigned int che unsigned long vanno in overflow, se si comportano allo stesso modo dovrebbero :

  • O funzionare entrambi, semplicemente andado in overflow in momenti diversi e ripartendo da zero
  • Oppure bloccarsi entrambi nel momento dell'overflow, che capitera' in momenti diversi

l'attuale situazione invece e' che Unsigned Int blocca il codice all'overfow, Unsigned Long non lo blocca mai, nemmeno dopo l'overflow

E' il casting. Avevo ragione io. Ed anche lesto aveva visto bene con la storia del complemento a 2.

Ho usato questo codice:

unsigned long Tempo;
int  ScrollTime;
const byte LED=13;
boolean stato=true;
unsigned long secondi;

void setup () {
    delay(2000);
    pinMode(LED, OUTPUT);
    digitalWrite(LED, stato);
    Serial.begin(19200);
    Serial.println("Partito");
    secondi=seconds();
}

void loop () { 
Tempo=millis();

    if (secondi!=seconds()) {
        secondi=seconds();
        Serial.println(ScrollTime + 300, DEC);
    }
    if (Tempo > ScrollTime + 300) {
        stato ^= true;
        digitalWrite(LED, stato);
        ScrollTime = millis();
    } 
}

(usa la funzione seconds() che ho presentato alcuni giorni fa).
Dopo una trentina di secondi sul terminale compare SEMPRE il valore -32527.

Usando questo codice, con unsigned int ScrollTime si ha un risultato inatteso.

unsigned long Tempo;
unsigned int  ScrollTime;
const byte LED=13;
boolean stato=true;
unsigned long secondi;

void setup () {
    delay(2000);
    pinMode(LED, OUTPUT);
    digitalWrite(LED, stato);
    Serial.begin(19200);
    Serial.println("Partito");
    secondi=seconds();
}

void loop () { 
Tempo=millis();

    if (Tempo > ScrollTime + 300) {
        Serial.println(ScrollTime, DEC);
        stato ^= true;
        digitalWrite(LED, stato);
        ScrollTime = millis();
    } 
}

Dopo circa 60 secondi, durante i quali la stampa è cadenzata a circa 0,3s di intervallo, il codice arriva a passare 65535 (il max valore di un unsigned int) e sul terminale l'Arduino comincia a stampare TUTTI i valori di ScrollTime. In pratica entra infinite volte nel ciclo, dando l'apparenza di essere bloccato (perché il Led è acceso fisso) ma in realtà ne cambia lo stato talmente in fretta che l'occhio umano non riesce a distinguere il passaggio.

Confermo i due test, invece del led ho usato lo scroll di un display, con int si blocca e con unsigned int lo scroll parte a razzo ed il display e' illeggibile.

Non ho capito ancora se questi comportamenti sono normali, e perché con unsigned long non capita.

3 variabili, 3 comportamenti diversi in zona overflow

ok, mi avete fatto tirare fuori l'arduino.

Prima di tutto una cosa che centra nulla ma volevo testare:

con Serial.print(' '); lo skecth misura 2888byte: invece con Serial.print(" "); misura 2896 byte! quindi se scrivete un solo carattere privilegiate l'apice singolo!
certo una differenza di 8byte è tanta.. bha

comunque le sto provando tutte e effettivamente non riesco a capire cosa diavolo succeda.

il mio test per ora... ora proseguo per capire se per caso c'è una flag(o bug) assegnata ad ogni variabile che ne identifica l'overflow e rende sempre veri gli if

unsigned long Tempo;
unsigned int  ScrollTime;
const byte LED=13;
boolean stato=true;
unsigned long tempo2;
unsigned int *p;

void setup () {
    delay(2000);
    pinMode(LED, OUTPUT);
    digitalWrite(LED, stato);
    Serial.begin(115200);
    Serial.println("Partito");
}

void loop () { 
  Tempo=millis();

    if (Tempo > (unsigned long)(ScrollTime + 50)) {
      tempo2 = ScrollTime+50;
//      ScrollTime = tempo2;
/*
      Serial.print(tempo2, DEC);
      Serial.print(' ');
      Serial.print(tempo2, BIN);
      Serial.print(' ');

      Serial.print(ScrollTime + 50, DEC);
      Serial.print(' ');
      Serial.print(ScrollTime + 50, BIN);
      Serial.print(' ');
      */
      Serial.print(ScrollTime, DEC);
      Serial.print(' ');
      Serial.print(ScrollTime, BIN);
      Serial.print(' ');
      Serial.print(Tempo, DEC);
      Serial.print(' ');
      Serial.print(Tempo, BIN);
      /*
      p = (unsigned long *)&Tempo;
      Serial.print(' ');
      Serial.print( (*p), BIN);
      tempo2 = Tempo;
      Serial.print(' ');
      Serial.print(tempo2, DEC);
      Serial.print(' ');
      Serial.print(tempo2, BIN);
      */
      p = &ScrollTime;
      Serial.print('p');
      Serial.print( (*p), BIN);

      p = &ScrollTime+1;
      Serial.print('+');
      Serial.print( (*p), BIN);

      p = &ScrollTime-1;
      Serial.print('-');
      Serial.print( (*p), BIN);
      
      
      unsigned long *a;
      p = &ScrollTime;
      a = (unsigned long *)p;
      Serial.print('a');
      Serial.print( (*a), BIN);
      p-=sizeof(unsigned long);
      p+=sizeof(unsigned int);      
      a = (unsigned long *)p;
      Serial.print('A');
      Serial.print( (*a), BIN);
      Serial.print('A');
      Serial.print( (*a), DEC);
      
      p = &ScrollTime;
      p+=sizeof(unsigned long);
      p-=sizeof(unsigned int);      
      a = (unsigned long *)p;
      Serial.print('B');
      Serial.print( (*a), BIN);
      Serial.print('B');
      Serial.print( (*a), DEC);
      
      if ((*a) < 135593984){
        (*a)=135593984;
      }
      
      Serial.println();
      /*
      if (Tempo > 70000L){
        while(1);//stop!!
      }
      */
      stato ^= true;
      digitalWrite(LED, stato);
      ScrollTime = millis();
    } 
}

altro test più "barbaro":

unsigned long Tempo;
unsigned int  ScrollTime;
const byte LED=13;
boolean stato=true;
unsigned long secondi;

void setup () {
    delay(2000);
    pinMode(LED, OUTPUT);
    digitalWrite(LED, stato);
    Serial.begin(19200);
    Serial.println("Partito");
}

void loop () { 
    Tempo+=1;

    if (Tempo > ScrollTime + 300) {
        Serial.println(ScrollTime, DEC);
        stato ^= true;
        digitalWrite(LED, stato);
        ScrollTime = Tempo;
    } 
}

e la parte incriminata:

64715
65016
65317
65318
65319
65320
65321
65322
65323
65324
65325
65326
65327
65328
65329
65330
65331
65332
65333
65334
65335
65336
65337
65338
65339

da li in poi tutto procede al peggio.

con

unsigned long Tempo;
unsigned int  ScrollTime;
const byte LED=13;
boolean stato=true;
unsigned long secondi;

void setup () {
    delay(2000);
    pinMode(LED, OUTPUT);
    digitalWrite(LED, stato);
    Serial.begin(19200);
    Serial.println("Partito");
}

void loop () { 
    Tempo+=1;

    if (Tempo >= ScrollTime + 300) {
      Serial.print('S');
        Serial.println(ScrollTime, DEC);
        Serial.println(Tempo, DEC);
        stato ^= true;
        digitalWrite(LED, stato);
      Serial.print('T');
        Serial.println((Tempo - (ScrollTime + 300)), DEC);
        if (Tempo - ScrollTime < 300){
          Serial.println("azz");
        }
        ScrollTime = Tempo;
    } 
}

mi sono accorto che è proprio la matematica ad essere sbagliata!

quando entriamo nell'if, in teoria (Tempo - (ScrollTime + 300) dovrebbe essere sempre = 0 salvo overflow.
da 0 a 65400 tutto ok, a 65401 (valore alquanto bizzarro) l'operazione da SEMPRE 65237 come risultato.

notare che l'if Tempo - ScrollTime < 300 però è corretto, per via del cast "fatto giusto"

ogni idea che mi viene in mente si schianta su quel 65401.

uau, questo bug risale la classifica dei bug piu' interessanti che io abbia mai scovato :slight_smile:

probabilmente non e' mai venuto fuori perche' la gente usa di default Unsigned Long.

Testato:
uau, questo bug risale la classifica dei bug piu' interessanti che io abbia mai scovato :slight_smile:

Sicuro ?
Io dico che il bug è l'essere umano, però non vi dico perché, ci dovete arrivare da soli :smiley:

E' un problema di casting tra tipi differenti.
Come ha spiegato Astro ogni compilatore affronta il problema in maniera differente per cui non può esistere una regola certa ed unica. Non è un caso come "a+=1" che tutti i compilatori devono trattare in una certa maniera perché è una regola del C.

Qui stai sfruttando dei comportamenti anomali, e la regola sarebbe di non usare mai queste anomalie perché potrebbero dare risultati inattesi nel codice. Il fatto che con unsigned long non dia problemi conferma proprio che se togli al compilatore i "dubbi" su come comportarsi hai un codice che fa ciò che vuoi tu e non ciò che decide per te avr-gcc.

Se lesto ci sta sbattendo la testa mi ritengo giustificato per l'impreparazione :slight_smile:

OT, nella spiegazione del tipo float c'e' scritto:

Floating-point numbers can be as large as 3.4028235E+38

mi dite come si interpreta quel E+38
thanks :slight_smile:

Testato:
mi dite come si interpreta quel E+38

Il formato float è di tipo esponenziale, cioè una mantissa ed un esponente, pertanto consente di rappresentare numeri enormi, molto di più di quelli rappresentabili con un long, però la precisione è di poche cifre significative, con un float a 32 bit al massimo 7 cifre in totale, tutte le restanti sono zeri.