Funzioni in C

Vi chiedo gentilmente un aiuto per comprendere meglio le funzioni.

Ho letto che è possibile passare dei parametri ad una funzione e di riceverne di ritorno dei risultati.
Però ho visto che se una variabile è definita come globale all'inizio del programma e questa variabile muta all'interno della procedura, quando la funzione termina, viene comunque restituito il nuovo valore che la variabile ha assunto dentro la funzione.
Dunque non capisco il senso di RETURN e nemmeno il motivo per cui vanno usate funzioni in cui si passano parametri.
Ad esempio ho scritto questa procedura per tarare i sensori di flessione dando avvisi luminosi per sapere quando vanno tenuti diritti e quando vanno piegati.

void taratura() {
  digitalWrite (8, HIGH);
  delay (4000);
  for (int z=1; z<20; z++){
    digitalWrite (8, HIGH);
    delay ((200)-(9*z));
    
  max1 = analogRead(1);
   max2 = analogRead(2);
   max3 = analogRead(3);
   max4 = analogRead(4);
   max5 = analogRead(5);
   digitalWrite (8, LOW);
   }
  delay (1000);
  digitalWrite (7, HIGH);
  delay (4000);
   for (int z=1; z<20; z++){
    digitalWrite (7, HIGH);
    delay ((200)-(9*z));
  min1 = analogRead(1);
  min2 = analogRead(2);
  min3 = analogRead(3);
  min4 = analogRead(4);
  min5 = analogRead(5);
  digitalWrite (7, LOW);
   }
  delay (1000);
  }

All'uscita della procedura ottengo i valori necessari per stabilire i range entro cui far ruotare i servo.

edit by mod: includere il codice usando gli appositi tag

Funzione banalissima per dimostrare le potenzialitá delle funzioni:

int somma ( int A ,int B)
{
return (A+B);
}

adesso se vuoi fare la somma di 2 variabli chiami la funzione e gli dai le due vaiabili:

risultato = somma ( variabileA, VariabileB);

se adesso vuoi fare la somma di due altri variabili e ti serve il risultato in un altra variaible

sum = somma ( variabileC , VariabileD);

cosí puoi usare una funzione per qualsiasi variabile dello sketch che lavorando con variabili globali senza passare dei valori alla funzione non sarebbe possibile.

Ciao Uwe

Le funzioni ti permettono di riutilizzare il codice, evitando ripetizioni. Poichè i parametri sono variabili locali della funzione si riducono anche le possibilità di fare errori grossolani come modificare qualcosa che serve ancora o dichiarare una stessa variabile e poi usarla per due cose contemporaneamente all'interno del codice.
In progetti molto grandi aiutano a mantenere il codice leggibile e a modificarlo anche dopo mesi che non lo guardi più.
Infine aiutano nel lavoro di squadra permettendo una divisione dei compiti altrimenti impossibile.

Le spiegazioni precedenti sono perfette.
Mi permetto di aggiungerti un esempio:

Nel tuo sketch hai usato ad esempio la funzione digitalWrite (7, LOW);
Perciò il primo parametro varrà 7 e il secondo LOW.
Se non esistessero i parametri tu dovresti passare i due valori attraverso due variabili globali di cui dovresti anche conoscerne il nome, oltre a sapere che la digitalWrite si aspetta 2 valori.

x iscrizione

Testato:
x iscrizione

???

!!! :slight_smile:

*** :stuck_out_tongue_closed_eyes:

Testato:
x iscrizione

No, non ci credo, testato non ha ancora capito come usare le funzioni. ]:smiley:

Ciao.

Grazie per le spiegazioni.
Ho capito che in una visione organica del codice usare variabili globali anche all'interno delle funzioni può risultare pericoloso.
Tuttavia la cosa è possibile e presenta anche i suoi vantaggi visto che non è necessario passare i dati nella chiamata o restituirne altri al termine della funzione.
L'esempio della somma di due variabili è perfetto per spiegare i vantaggi del passare i dati, mentre se devo attivare la rotazione in un senso o nell'altro di un motore mi limiterò a settare i pin necessari dentro le funzioni (facendone due, una per la rotazione oraria e l'altra per quella antioraria) senza bisogno di trasferimento di valori.
Potrei anche farne una sola, ma concettualmente mi sembra che chiamare le funzione "motoresu" o "motoregiu" è più semplice che definirne una sola generica "motore" e poi dover ricordare i valori da passare per la salita o la discesa.

Grazie ancora :slight_smile:

Mauro non è che non so come usarle, non le conosco proprio :slight_smile:

Onestamente anche io le uso sempre senza argomenti e dichiarate void, usando a palla variabili globali.
Mi risulta tutto piu leggibile e facile

Mai scritta la parola Return in vita mia
Ci sono grosse controindicazioni ?

L esempio motore su e giu mi sembra molto calzante. Inoltre divido a piu non posso le funzioni in tab diverse e mi risulta tutto leggibile e ordinato invece di lunghissimi codici su tab singola ,

@Dorsai:
Quelle che fai tu sono procedure (praticamente funzioni senza return o meglio, con return da solo senza valore e implicito nel caso non fosse messo). Come indica il nome sintetizzano il concetto di richiamo di una procedura fissata per fare qualcosa di già esistente. Le funzioni vengono usate più che altro quando si fa ha che fare con algoritmi complessi che è più facile vedere come blocchi che comunicano tra loro. Le funzioni dopotutto derivano dalla matematica dove servono per unire operazione e operandi in nuovi operandi più gestibili (tan(x) la tratti come la tangente di x e ti le concatenazioni più chiare).

@Testato:
In ambito di microcontrollori a 8 bit e semplici firmware le procedure ci possono stare (anzi, danno virtualmente meno problemi in esecuzione perchè richiedono meno memoria che è anche determinabile con sicurezza) mentre se si va su cose più raffinate è meglio introdurre anche qualche funzione. Le procedure se sono molto piccole si potrebbero dichiarare inline così non hai nemmeno l'overhead (poi dipende anche dalla qualità del compilatore che dovrebbe capire come ottimizzare il codice).

Grazie yoshi della conferma e chiarificazione.
Da oghi quindi le chiamo procedure :slight_smile:

Hai il tuo primo karma :slight_smile:

Che significa inline ed overhead ?

Paese che vai, nome che trovi.
Le funzioni senza parametri io le chiamo "routine". Sono entrambi nomi validi ed indicano come "funzione" un blocco di programma separato dal loop principale che può essere chiamato da più punti del programma, sia dal loop che da altre funzioni.

Detto questo, le funzioni o le procedure/routine servono per semplificare il programma. Esse vanno a sostituire dei blocchi di codice ripetitivi. L'esempio del digitalWrite è esplicativo: dentro al digitalWrite ci sono diversi controlli: esistono delle chiamate a delle macro che trasformano il numero di pin logico nel piedino fisico del microcontrollore, viene controllato se il pin è capace di Pwm, in caso affermativo viene spento questo segnale, e poi viene impostata il registro della porta per generare lo stato voluto. Tutto questo è noioso e lungo da mettere mettiamo 10 volte in un programma. Allora è stata creata la routine o funzione o procedura (chiamala come ti pare) che accetta un numero di pin ed uno stato e provvede ad eseguire quel compito.

Poi non esiste una regola valida per tutti. Non è detto che una funzione alleggerisca il programma. Come ti ha spiegato yoshi, le funzioni appesantiscono l'elaborazione perché nel momento in cui il programma ne incontra una il compilatore deve prevedere di salvare nello stack l'indirizzo del PC (il Program Counter, il registro che punta alla cella di memoria che contiene l'istruzione da eseguire), poi passare gli eventuali valori, saltare alla funzione, eseguirla, salvare eventuali valori da restituire al chiamante, riestrarre il PC, tornare al punto precedente e ripartire da lì.
Quindi se ti fai una funzione per 2 righe di codice secche l'aggravio è superiore ai vantaggi ottenibili.

leo72:
Paese che vai, nome che trovi. Le funzioni senza parametri io le chiamo "routine". Sono entrambi nomi validi ...

Penso che chi arriva da Basic o Pascal sia abituato a chiamarle procedure (all'italiana) perchè in quei linguaggi vengono distinte dalla funzioni (procedure/function)

Sono procedure in VB, se hai usato i vecchi Basic anni '80 le chiamavi subroutine anche te :wink:
E si invocavano con un bel GOSUB, ricordi? :stuck_out_tongue:

Ma comunque le si chiamino, sono porzioni di codice che eseguono un determinato compito e che possono essere invocate con un nome, con o senza parametri, con o senza valori indietro. Il succo non cambia.

Testato:
Che significa inline ed overhead ?

prendi la cosa con le pinze, ma credo che "inline" dice al compilatore di inserire in quel punto le istruzioni che sono all'interno della funzione richiamata. Invece senza la parola "inline" quando si arriva alla chiamata della funzione succede quello che ha detto Leo, portando un overhead. Questo è quello che ho capito, ma potrebbe essere completamente sbagliato :~

@andrea86: hai capito bene.
Per la cronaca: inline sostituisce i #define del C nel caso delle funzioni permettendo al compilatore di effettuare tutti i controlli necessari ed evitando bug legati alle precedenze delle varie operazioni.

@leo72: io chiamo subroutine/routine le procedure in assembly :slight_smile: .

yoshi93:
@leo72: io chiamo subroutine/routine le procedure in assembly :slight_smile: .

Esattamente! :wink:
Programmavo anch'io in assembly.... tanti anni fa :sweat_smile:

Testato:
Inoltre divido a piu non posso le funzioni in tab diverse e mi risulta tutto leggibile e ordinato invece di lunghissimi codici su tab singola.

Questo mi sembra molto interessante.
Solo che non ho capito come si fa :~