Go Down

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

SukkoPera

In sostanza quindi non c'è quasi differenza (anche se io preferisco in genere le #define perché per convenzione i simboli sono in maiuscolo e li distinguo così dalle variabili normali).
In verità il maiuscolo si tende ad usare per le costanti in generale, indipendentemente dal fatto che siano #define o 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

Standardoil

All'ora, ho provato così:
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)++;
}

e indovinate cosa esce....
Stop alla musica, Rullo di tamburi..... Proiettori sul palco, grazie.....
Code: [Select]

La costante vale: 100
Però adesso vale: 100

che figuraccia......
da andare a nascondersi....



P.S. aspettiamo prossima puntata
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

Quello che hai fatto credo sia proprio undefined behavior, per cui non vuol dire niente. Non dà warning in compilazione?
"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

Ritenta sarai più fortunato -> Nessun warning
comunque perchè undefined behavior? non c'è nessuna ambiguità in quello che ho scritto
modificare una variabile puntata da un puntatore valido NON è sbagliato.....
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ù

nid69ita

#19
Feb 07, 2019, 08:02 pm Last Edit: Feb 07, 2019, 08:04 pm by nid69ita
In realtà, se nella #define tu specifichi il tipo (invece che lasciare int di default), ecco che NON risparmi un bel nulla e le due cose tornano equivalenti:

Code: [Select]
#define VALORE (byte)84
void setup() {
 int p = VALORE;
 p += VALORE;
 Serial.println(VALORE);
}

... ti darà la stessa occupazione del tuo "const byte VALORE = 84;" :D

Guglielmo
Diavolaccio !!   :smiley-evil: :smiley-evil:   :smiley-mr-green:               


P.S. Che brutto però un cast in un define (non mi piace molto)
Ricordiamo poi quello che disse (giustamente) @astro,   non è detto che tutti i compilatori, dato gli esempi fatti con la const, la trattino alla pari di un define;  ovvero non è detto sia portabile. 
my name is IGOR, not AIGOR

Standardoil

#20
Feb 07, 2019, 08:14 pm Last Edit: Feb 07, 2019, 08:14 pm by Standardoil
Diavolaccio !!   :smiley-evil: :smiley-evil:   :smiley-mr-green:               


P.S. Che brutto però un cast in un define (non mi piace molto)
Ricordiamo poi quello che disse (giustamente) @astro,   non è detto che tutti i compilatori, dato gli esempi fatti con la const, la trattino alla pari di un define;  ovvero non è detto sia portabile.
Nemmeno a me piace troppo castare, men che meno in una macro
ma separiamo il luppolo dall'olio (o forse la citazione non è proprio così..........)
la #define è una direttiva di PRE-compilatore, il compilatore non c'entra nulla, si tratta di una pura sostituzione di testo
Semmai alcuni compilatori possono trattare trattare variabili definite "const", inizializzate a valore pre-conosciuto e non movimentate come se fossero scritte "hard coded", ma sarebbe una ottimizzazione dl compilatore e "deve" essere escludibile, come non lo so e non mi interessa, ma "deve" esserci, per poter usare "Extern" quelle variabili
ma questo non varrebbe ad esempio se io scrivessi una cosa del tipo
Code: [Select]

const int costante= analogRead(A0);

avrei una costante che non è definita a priori (a compile-time), in questo caso il compilatore ottimizzerà ben poco...
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

#21
Feb 07, 2019, 09:41 pm Last Edit: Feb 07, 2019, 09:42 pm by SukkoPera


Ritenta sarai più fortunato -> Nessun warning
comunque perchè undefined behavior? non c'è nessuna ambiguità in quello che ho scritto
modificare una variabile puntata da un puntatore valido NON è sbagliato.....
No, eh?
Code: [Select]
/home/sukko/Development/arduino/test/test.ino: In function 'void loop()':
/home/sukko/Development/arduino/test/test.ino:16:25: warning: invalid conversion from 'const int*' to 'int*' [-fpermissive]
     incrementa(&costante);
                         ^
/home/sukko/Development/arduino/test/test.ino:22:6: note:   initializing argument 1 of 'void incrementa(int*)'
 void incrementa(int * pointer)
      ^


Mica per niente:

Quote
Putting the address of a const type into a pointer to the unqualified type is [...] dangerous and consequently prohibited (although you can get around this by using a cast). Here is an example:

#include <stdio.h>
#include <stdlib.h>

main(){
 int i;
 const int ci = 123;

 /* declare a pointer to a const.. */
 const int *cpi;

 /* ordinary pointer to a non-const */
 int *ncpi;

 cpi = &ci;
 ncpi = &i;

 /*
 * this is allowed
 */
 cpi = ncpi;

 /*
 * this needs a cast
 * because it is usually a big mistake,
 * see what it permits below.
 */
 ncpi = (int *)cpi;

 /*
 * now to get undefined behaviour...
 * modify a const through a pointer
 */
 *ncpi = 0;

 exit(EXIT_SUCCESS);
}


As the example shows, it is possible to take the address of a constant object, generate a pointer to a non-constant, then use the new pointer. This is an error in your program and results in undefined behaviour.
(Da https://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html)

E se vuoi anche il riferimento allo standard:
Quote
The C Standard, 6.7.3, paragraph 6 [ISO/IEC 9899:2011], states


If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.
(Da https://wiki.sei.cmu.edu/confluence/display/c/EXP40-C.+Do+not+modify+constant+objects)

Ritenta ascoltando chi ne sa più di te, sarai più fortunato. O per lo meno farai meno figuracce.
"Code is read much more often than it is written, so plan accordingly. Design for readability."

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

nid69ita

la #define è una direttiva di PRE-compilatore, il compilatore non c'entra nulla
ovvio. 
Per inciso io ho scritto solo di const la non sicurezza che ogni compilatore lo ottimizzi.
my name is IGOR, not AIGOR

Standardoil

io non posto boiate
il codice che ho postato compila correttamente senza alcun warning e comportandosi correttamente
se vuoi ti metto l'output del compilatore non ho problemi
come linea di principio io parlo sempre a ragion veduta, vediamo di farcene una ragione, scusate il gioco di parole
il problema, anzi, il "tra virgolette problema" di quel codice è solo che la variabile
Code: [Select]

const int costante=100;

va in realtà dichiarata
Code: [Select]

volatile const int costante=100;

per avvisare il compilatore che NON deve fare ottimizzazioni su di essa
così facendo il programma si comporta correttamente
pronto a disposizione per postare programma e output di compilazione
come mai non vada a te, è un problema non mio..................
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

#24
Feb 07, 2019, 10:03 pm Last Edit: Feb 07, 2019, 10:07 pm by SukkoPera
Preciso che il warning di cui sopra l'ho ottenuto prendendo il tuo codice e compilandolo con Arduino 1.8.6. Se a te il warning non esce evidentemente hai un problema nell'installazione o hai zittito l'output, perché DEVE uscire.

Un programma si comporta correttamente quando il compilatore fa sì che faccia quel che descrive il suo codice sorgente nel rispetto dello standard del linguaggio. Nel caso in esame lo standard NON definisce cosa il compilatore debba fare per cui qualunque comportamento è giusto, anche ucciderti il gatto. E il fatto che tu ottenga due comportamenti diversi a fronte di una lieve modifica è la prova di questo. Anche perché se una qualunque ottimizzazione del compilatore modificasse il comportamento del programma, sarebbe un bug del compilatore.

Poi beh, capisco che tu non voglia credere a me (anche se sono probabilmente più qualificato di te), e nemmeno al primo sito che capita, ma almeno di fronte allo standard C dovresti avere l'umiltà di arrenderti.

Boh, ognuno crederà a chi vuole. Però noto che questa cosa dell'undefined behavior proprio non entra in testa a molti. In qualche altro thread avevo già litigato con qualcuno che non voleva ammettere che i = i++; fosse UB neppure a fronte del warning "behaviour might be undefined" emesso da GCC :smiley-confuse:.
"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

Mah, guarda
io non discuto con te, so che sei più qualificato
io uso il pinguino, con IDE 1.8.5, versione stand-alone, tutti i flag di spunta inseriti
non sono programmator per lavoro, quindi non sto nemmeno a pasticciare con le varie opzioni, quello che c'è lascio
al massimo ho installato qualche libreria, che però qui non uso........
adesso per curiosità provo la 1.8.6 stand-alone, giusto per prova, visto che comunque squadra che vince non si cambia
la "storia" di passare un puntatore a una funzione per modificare una costante non me la sono inventata io, la ho copiata, anche se non ricordo da dove, lo sto cercando adesso........
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

MA VUOI CAPIRE CHE NON SI FA E BASTA???

Se hai la necessità di modificare qualcosa che hai dichiarato const hai sbagliato a dichiararlo tale, punto. Non ti pare??? C'è davvero da discutere?
"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

Sì, concordo, ma tutto questo non ha nulla a che fare con l'argomento del topic
che è: "che differenze c'è tra const e #define"?
eccone una.....
che poi sia più o meno corretto fare quello che ho fatto, è evidente che una variabile col modificatore const alloca memoria, è indirizzabile e passabile per indirizzo, la #define non fa nulla di tutto questo
che poi sia sbagliato oppur no fare quello che ho fatto io NON è l'argomento del topic, grazie per l'interessamento.......... ma adesso chiudiamola!
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ù

maubarzi

Io sarei l'ultimo a dover parlare, ma...
permettere la modifica di qualcosa dichiarato const dopo la dichiarazione mi parrebbe un bel controsenso.
Però non mi è chiaro se usando i puntatori questo sia fisicamente possibile.
Il compilatore è sempre in grado di accorgersene? Lo impedisce fisicamente con un errore di compilazione o compilando ignorando l'operazione? oppure la permette?
Dal risultato in 16 pare abbia ignorato l'operazione.
Nessuna buona azione resterà impunita!

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

SukkoPera

#29
Feb 07, 2019, 11:14 pm Last Edit: Feb 07, 2019, 11:26 pm by SukkoPera
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.

Forse ci siamo persi un po' di cose, ricapitoliamo:
- #define fa una sostituzione testuale, per cui per forza di cose non viene allocata alcuna variabile ed è come scrivere il valore direttamente al posto del nome della costante.
- const messo davanti ad una variabile dice al compilatore "questa variabile non dovrebbe mai cambiare valore, se lo cambio cazziami", e questo viene fatto tramite warning o errori di compilazione.
- 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.
- Di solito i compilatori prevedono diversi livelli di "furbizia" (= ottimizzazione), da "nessuna" (= spreca memoria) a "esagerata" (= impiega ore a compilare nel tentativo di migliorare le performance), passando per "pancia piatta" (= risparmia più memoria possibile o riduci la dimensione dell'eseguibile il più possibile).
- Essendo gcc PARECCHIO furbo mi aspetto che (con le ottimizzazioni attive) 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.
- Andare a modificare una cosa dichiarata const, sebbene fattibile attraverso sotterfugi (che quasi sempre producono almeno un warning), risulta in UNDEFINED BEHAVIOUR, ovvero qualunque cosa il compilatore faccia, dal niente allo scatenare la 3a guerra mondiale, ricade perfettamente nello standard e non si può dire che sia sbagliato.
- Ci sono altri casi di undefined (o unspecified) behaviour, è compito del programmatore tenersene alla larga.

Tutto chiaro?
"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