#define e const byte e le loro reali differenze

Altra stupida domanda, tanto quanta quella posta sullo switch...

#define mioLed 1
const byte mioLed = 2;

Quale usereste delle due, ma soprattutto per quale motivo (memoria RAM, prestazioni, correttezza di definizione secondo voi o secondo il compilatore)...

NOTA: pongo queste domande perché a volte usiamo entrambi le modalità di definire i pin, ma alcuni (proprio come me) non sanno quello che effettivamente varia all'interno del compilatore nonché dell'mcu... Se fossero uguali non avrebbe senso avere due modi di scrivere diversi... Quindi, qualcuno di buon animo, sarebbe disposto a scambiare due chiacchiere? OT: prevedo già qualcuno che mi indica dove devo andare a leggere... :smiley: :smiley:

miky_police:
Altra stupida domanda, tanto quanta quella posta sullo switch...

... e niente eh, non c'è nulla da fare, quando uno è pigro è pigro ! :smiling_imp: :smiling_imp: :smiling_imp:

E' cosa di cui si è parlato tante volte sul forum e basta fare una piccola ricerca per trovare vecchie discussioni, come QUESTA. Alla fine del thread, la risposta di Astrobeed, è esauriente.

Guglielmo

P.S.: In fondo a tutti i mei post, lo vedi il testo in "firma" ? :smiling_imp:

ok... ricevuto... se solo potessi usare quel report to moderator :smiley: :smiley: :smiley:
Come al solito GRAZIE...

Ovviamente chiunque avesse qualcosa da aggiungere al riguardo (magari con esempi banali), seguo il post con interesse...

Grazie ancora gpb01.

Se ho capito bene per singole variabili sono uguali. Solo che #define é un "cerca e sostituisci", quindi non crea la variabile (può anche essere usato per creare finte funzioni o accorciare pezzi fi codice ripetuti) mentre const la crea, e per questo puoi farne array, se fosse più comodo. Personalmente const po uso solo in caso di array, per singole variabili uso #define

Chiaramente quando dico " variabili" intendo non modificabili

Silente:
Chiaramente quando dico " variabili" intendo non modificabili

... e allora usa il termine giusto ... costanti ! :smiling_imp:

Guglielmo

@silente, per me la differenza più grande è che una #define per una costante NON ne definisce il tipo.
Ovvero se io creo #define MIONUM 10 non ho detto se quel 10 è int, long o altro.
Invece una const comunque vuole il tipo. E quindi il compilatore non "interpreta" ma del tipo del dato lo hai informato tu.

No, fermi, const alloca memoria
Che poi il compilatore non ti lascia più modificare, li dove la hai "const"....atata
Ma magari in altri moduli, sì
Ovvero una variabile può essere const in un modulo, in una specifica funzione, ma non in un'altra
Rimangono variabili, che possono essere dichiarate extern in altri moduli, che possiedono un indirizzo e che possono essere passate per riferimento in C++ (questo non sono sicuro, non programmo in C++)
e aggiungo, passo ad una funzione l'indirizzo di una const, la funzione lo tratta come un puntatore a variabile, ecco modificata una const senza nemmeno doverla dichiarare extern in un altro modulo

Standardoil:
No, fermi, const alloca memoria ...

... lo hai letto il thread che ho linkato al mio post #1 ? ... mi sembra di no ... ::slight_smile:

Guglielmo

Oltre alla lettura del link di Guglielmo, intanto c'è la logica, ossia se io ho una
#define VALORE 584
quel simbolo (VALORE) il compilatore lo sostituisce in tutto il codice quando compila.
Per cui basta fare qualche prova ad esempio:

#define VALORE 584
void setup() {
  int p = VALORE;
  p += VALORE;
  Serial.println(VALORE);
}

equivale a:

void setup() {
  int p = 584;
  p += 584;
  Serial.println(584);
}

Entrambi (Arduino UNO) occupano esattamente 1600 byte per il programma e 188 byte di RAM.

Usare la const ossia:

const int VALORE = 584;
void setup() {
  int p = VALORE;
  p += VALORE;
  Serial.println(VALORE);
}

porta sempre a 1600 byte di programma e 188 byte di RAM.
Si può "risparmiare" invece qualcosa se il valore ad esempio fosse un byte:

const byte VALORE = 84;
void setup() {
  int p = VALORE;
  p += VALORE;
  Serial.println(VALORE);
}

che porta il programma a 1416 byte e sempre 188 di RAM.

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).

gpb01:
... lo hai letto il thread che ho linkato al mio post #1 ? ... mi sembra di no ... ::slight_smile:

Guglielmo

invece si, letto. Anzi già letto in precedenza
In cosa contrasta con quello che ho detto io?
Forse che non puoi passare l'indirizzo di una const?
Forse che non puoi avere un puntatore a const?
Forse che non puoi eguagliare un puntatore a variabile all'indirizzo di una const?
Tutte queste cose non si fanno con le #define

nid69ita:
@silente, per me la differenza più grande è che una #define per una costante NON ne definisce il tipo.
Ovvero se io creo #define MIONUM 10 non ho detto se quel 10 è int, long o altro.
Invece una const comunque vuole il tipo. E quindi il compilatore non "interpreta" ma del tipo del dato lo hai informato tu.

Questo è il punto principale!

Inoltre, una const in teoria alloca memoria, ma un compilatore un po' sveglio è in grado di evitarlo facendo la stessa sostituzione che farebbe con una #define. Da qualche parte gpb aveva anche fatto un test di disassembly per provare questo.

In sostanza: meglio una const ovunque possibile, almeno eventuali errori di tipo sono subito beccati dal compilatore. Dove non è possibile, si va di #define.

Un ultimo dettaglio: l'uso ad oltranza di #define è tipico del C, perché non è possibile fare questo:

const int N = 10;
char str[N] = "ciao";

... in quanto gli array devono avere una dimensione fissa e nota a tempo di compilazione (e const significa più "a sola lettura" che "costante"). In C++, invece, la cosa è perfettamente legale, per cui si assiste ad utilizzi di #define più limitati. In teoria, il C++ prevede anche l'uso delle funzioni inline al posto delle macro (cosa poi introdotta anche in C99, mi pare), proprio per eliminare il più possibile i #define, che spesso sono causa di errori e/o incasinamenti generali.

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:

#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;" :smiley:

Guglielmo

Standardoil:
invece si, letto. Anzi già letto in precedenza
In cosa contrasta con quello che ho detto io?

... guarda COSA ho quotato ... pare che qualcuno avesse detto che const non alloca memoria ...

Guglielmo

... perciò, dagli esperimenti di docdoc al #8 e da quanto detto da SukkoPera al #10:

"Inoltre, una const in teoria alloca memoria, ma un compilatore un po' sveglio è in grado di evitarlo facendo la stessa sostituzione che farebbe con una #define."

sembra che, senza offesa, l'IDE non sia "un po' sveglio"... :slight_smile:

Datman:
sembra che, senza offesa, l'IDE non sia "un po' sveglio"... :slight_smile:

No, sei TU che stai sbagliando ... 84 così senz'altra specifica è un "int" (che è il tipo di default se non si specifica nulla), mentre nella tua "const" tu per 84 specifichi chiaramente che vuoi un byte e allora ... devi specificarlo anche nella #define.

Guglielmo

docdoc:
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.

All'ora, ho provato così:

// 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.....

La costante vale: 100
Però adesso vale: 100

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

P.S. aspettiamo prossima puntata

Quello che hai fatto credo sia proprio undefined behavior, per cui non vuol dire niente. Non dà warning in compilazione?

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.....

gpb01:
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:

#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 !! :smiling_imp: :smiling_imp: :grin:

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.