Go Down

Topic: #define e const byte e le loro reali differenze (Read 1 time) previous topic - next topic

Standardoil

no, al #16 non ha ignorato l'operazione, ma ha erroneamente ottimizzato per non ri-leggere la variabile alla stampa successiva
forzarla volatile obbliga il compilatore a ri-leggere sempre le variabili dalla memoria, e se si fa così, magia, il valore viene "correttamente" mostrato modificato
correttamente tra virgolette, dato che non è corretto farlo, su questo sono d'accordo con Sukko
ma lo fa, lo permette, generando (ma a me no, la 1.8.5 no, la 1.8.8 appena scaricata sì) un paio di warning, che a rigore NON interrompono la compilazione, segnalano solo al programmatore: "Ma sei sicuro sicuro di quello che stai facendo?, va' che io lo faccio, poi dopo sono cavoli tuoi........"
se il programmatore è "sicuro sicuro" fa un bel cast a int * e così convince il compilatore a non dare warning, ed ecco che la variabile const viene modificata senza warning
poi che sia corretto... non lo è!
però ci sono altri casi, meno estremi, nei quali una variabile puo' essere const da una parte e non cosnt da un'altra
Code: [Select]


// versione 2
int variabile = 100;
void setup(void)
{
    Serial.begin(9600);
}

void loop(void)
{
    Serial.print("La variabile vale: ");
    stampa(variabile);
    incrementa(&variabile);
    Serial.print("Adesso vale: ");
    stampa(variabile);
}


void stampa(int costante)
{
    Serial.print(costante);
    Serial.println(" ma da qui non la posso modificare");
}

dove evidentemente la stessa variabile è modificabile da una funzione, costante per un'altra
eggia' che una variabile sia modificabile da una funzione è un po' strano per il 'C'
Prima legge di Nelson (che sono io): La risposta giusta si può ottenere solo dalla domanda giusta, domande sbagliate danno risposte inutili

Non bado a studenti, che copino altrove

Hai problema-Ti domando-Non rispondi: Non ti serve più

SukkoPera

C'è una cosa che continua a sfuggirti: ciò che è CORRETTO e ciò che non lo è non lo decidi tu, bensì lo standard C a cui il compilatore aderisce!

Ciò che è CORRETTO secondo lo standard non sempre corrisponde a ciò che TU TI ASPETTI sia corretto.

Nel caso specifico, lo standard NON SPECIFICA quale sia il comportamento corretto da tenere, per cui non esiste nessun comportamento corretto (oppure lo sono tutti, a seconda di come la vuoi vedere).

Cosa non è chiaro di tutto questo?
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

Standardoil

#32
Feb 07, 2019, 11:27 pm Last Edit: Feb 07, 2019, 11:28 pm by Standardoil
Il compilatore se ne accorge quasi sempre (puoi far sì che non se ne accorga giocando coi puntatori, ma siamo sempre lì: PERCHÉ dovresti farlo???). In ogni caso, se fai una cosa del genere il compilatore non ha direttive precise da seguire (UB), per cui può succedere qualunque cosa, e questo è stato dimostrato da Standardoil che con una piccola modifica ha ottenuto due comportamenti diversi.

- Qualunque compilatore un po' furbo non andrà a sprecare memoria per qualcosa che non cambia mai, e di fatto produrrà lo stesso codice che se si fosse usato #define.
- Un compilatore non è tenuto ad essere furbo per rispettare lo standard C, è solo tenuto a rispettare i comportamenti che lo standard descrive, come lo fa è una scelta sua.


- Essendo gcc PARECCHIO furbo mi aspetto che anche senza const, se le circostanze lo permettono, non allochi memoria per una variabile ma la tratti al pari di una costante e quindi di una #define.
coe al solito dissento in qualcosa, non avermene a male
io non ho ottnuto due comportamenti differenti a causa dello UB, ma perchè il compilatore, NON sapendo che la variabile veniva modificata, ottimizzava,
la conferma si ottiene facile, basta far stampare la variabile (NON volatile) sia dalla loop che dalla incrementa
Code: [Select]

// di Nelson "StandardOil"
// Idea da sviluppare:
// Prova 'const' non costanti

void setup(void)
{
  Serial.begin(9600);
}

void loop(void)
{
  const int costante = 100;
  Serial.print("La costante vale: ");
  Serial.println(costante);
  incrementa(&costante);
  Serial.print("Però adesso vale: ");
  Serial.println(costante);
  delay(1000);
}

void incrementa(int * pointer)
{
  // incrementa una variabile
  (*pointer)++;
  Serial.print("e qui vale: ");
  Serial.println(*pointer);
}

 è la stessa ragione per cui dobbiamo dichiarare volatile le variabili usate nelle ISR , anche ho dovuto dichiarare volatile la char array che conteneva il carico pagante, nel mio crivello universale di pochi giorni fa
come ho già detto tempo fa, un compilatore che ottimizzasse troppo e non allocasse variabili const sbaglirebbe, const si riferisce allo scope del file corrente, se un progetto avesse più di un file sorgente (che non è il caso di arduino, concordo) e avesse le stesse variabili Extern queste devono venire allocate
Prima legge di Nelson (che sono io): La risposta giusta si può ottenere solo dalla domanda giusta, domande sbagliate danno risposte inutili

Non bado a studenti, che copino altrove

Hai problema-Ti domando-Non rispondi: Non ti serve più

Standardoil

C'è una cosa che continua a sfuggirti: ciò che è CORRETTO e ciò che non lo è non lo decidi tu, bensì lo standard C a cui il compilatore aderisce!

Ciò che è CORRETTO secondo lo standard non sempre corrisponde a ciò che TU TI ASPETTI sia corretto.

Nel caso specifico, lo standard NON SPECIFICA quale sia il comportamento corretto da tenere, per cui non esiste nessun comportamento corretto (oppure lo sono tutti, a seconda di come la vuoi vedere).

Cosa non è chiaro di tutto questo?
Cosa NON E' CHIARO nel fatto che io sono d'accordo con te, ma NON C'ENTRA con l'argomento della discussione?
Prima legge di Nelson (che sono io): La risposta giusta si può ottenere solo dalla domanda giusta, domande sbagliate danno risposte inutili

Non bado a studenti, che copino altrove

Hai problema-Ti domando-Non rispondi: Non ti serve più

SukkoPera

Vabbeh, io ci rinuncio, non c'è peggior sordo di chi non vuol sentire.
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

maubarzi

Il compilatore se ne accorge quasi sempre (puoi far sì che non se ne accorga giocando coi puntatori, ma siamo sempre lì: PERCHÉ dovresti farlo???). In ogni caso, se fai una cosa del genere il compilatore non ha direttive precise da seguire (UB), per cui può succedere qualunque cosa, e questo è stato dimostrato da Standardoil che con una piccola modifica ha ottenuto due comportamenti diversi.
Il mio interesse riguarda comprendere fino a che punto sono protetto da eventuali errori, quindi se il compilatore mi intercetta il 100% dei casi sono a posto altrimenti ho comunque un margine di incertezza perchè aver fatto degli errori e non accorgermene subito.

Ovvio che con le tecniche di hacking riesco a scrivere quello che voglio su qualunque area di memoria, ma a parte queste "forzature", nei casi "normali" dovrei essere quanto meno avvisato.
Parlo di GCC, non dei compilatori in generale, perchè nei miei casi mi sa che userei sempre e solo questo o suoi derivati.
Nessuna buona azione resterà impunita!

Preistoria -> medioevo -> rinascimento -> risorgimento -> rincoglionimento!

SukkoPera

#36
Feb 08, 2019, 08:37 am Last Edit: Feb 08, 2019, 10:20 am by SukkoPera
E allora stai sereno, i casi normali sono coperti.

Credo che quello di cui stiamo parlando sia una direttiva del linguaggio, non una iniziativa di gcc. const int non è int, per cui avrai sempre almeno un warning se passi il primo ad una funzione che si aspetta il secondo, con qualunque compilatore.

Il C++ poi è ancora più pignolo, perché puoi avere metodi const che non puoi invocare se hai un puntatore ad un oggetto non const, ecc ecc.
EDIT: Ovviamente quanto sopra è permesso, quel che non lo è è chiamare un metodo non-const tramite un puntatore const.
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

miky_police

#37
Feb 20, 2019, 03:07 pm Last Edit: Feb 20, 2019, 03:08 pm by miky_police
Scusate, mi riprendo un attimo la scena... Intanto GRAZIE a tutti per le molteplici risposte, per le spiegazioni tecniche fornite e per il bel dibattito che se ne era formato... Adesso mi è molto più chiara la differenza, ma se posso (Standardoil non me ne dire) vado per le corte:
const int SOMMA;
Non mi vado a complicare la vita per una dichiarazione errata di una variabile che ho fatto io e non il compilatore... Che poi ci sia un modo, più o meno convenzionale/testato/non supportato, di "cambiare" il valore di una const, beh è un'altra storia... e comunque penso che sia sempre più facile pigiare 5 volte backspace con il "puntatore" alla fine di "const"  :D
Non è per ridicolizzare niente e nessuno... Anzi, devo studiare bene la parte dei puntatori, referenziare, dereferenziare, ecc..
Ultima domanda che mi è sorta a seguito delle affermazioni di SukkoPera... Per OTTIMIZZAZIONE intendi l'LTO?
Il vero stupido è colui che fa e rifa la stessa cosa aspettandosi risultati diversi. A.E.

SukkoPera

Intendo le normali ottimizzazioni di spazio occupato/performance, che avvengano durante la compilazione o durante il linking non inficia il discorso.
"Code is read much more often than it is written, so plan accordingly. Design for readability."

Guida rapida a ESP8266: https://goo.gl/kzh62E

Go Up