Newsgroup: it.hobby.elettronica.digitale
Titolo: differenze in linguaggio C

Salve!
Sto cercando di imaprare qualcosa sul linguaggio C, ho due libri dove sono 
riportai i listati molto simili:
#include <stdio.h>
int main () {
    printf("hello, world\n");
    return 0;
}
nell'altro invece:
#include <stdio.h>
main () {
    printf("hello, world\n");
}
Quali sono le differenze?

Enzo ha scritto:

Cos'è un gioco enigmistico? :-)
A parte gli scherzi: il primo listato definisce la funzione main con un 
valore di ritorno di tipo int, e quindi, prima di uscire ritorna un 
valore (0 in questo caso).
Il secondo invece no, e quindi secondo chi lo ha scritto non ha bisogno 
del return. In realtà, in C, se si dichiara una funzione di cui non 
viene specificato il valore di ritorno viene preso per default il tipo 
'int'. Quindi le 2 dichiarazioni sono a tutti gli effetti equivalenti. 
Nel secondo caso il compilatore probabilmente genererà un "warning", 
cioè un avvertimento per un probabile errore: si aspetta che la funzione 
ritorni qualcosa ma non vede nessun return al suo interno.
Inoltre, entrambe le dichiarazioni non specificano nessun parametro di 
ingresso (dopo main le parentesi sono vuote). Per renderlo più chiaro a 
chi legge il codice di solito si usa la parola chiave 'void', che 
significa 'vuoto'.
Per completare il tutto aggiungo che la funzione main è l'entry point 
del programma, ovvero la prima funzione chiamata dopo lo startup.
Può essere definita in 2 modi:
int main(void);
int main(int argc, char *argv[]);
Il primo è quello che hai già visto ed è quello tipicamente usato nelle 
applicazioni embedde, anche perchè non ci sono parametri da passare :-)
Il secondo è il modo classico usato nei programmi per PC: i 2 argomenti 
sono il numero e i parametri passati sulla riga di comando al momento 
dell'invocazione del programma.
Spero di essere stato utile,
Ciao

 Quali sono le differenze?
Fondamentalmente gli standard cui aderiscono, come ti hanno già detto in 
un caso o nell'altro potrai avere degli avvertimenti (o degli errori) 
secondo il compilatore che usi, cioè secondo lo standard che il 
compilatore segue.

 Quali sono le differenze?
La risposta potrebbe essere lunga e varia...
Però per semplicità diciamo che lo standard ANSI C prevede
che il main restituisca un int. Se non lo fai non succede niente,
al massimo hai un warning.
Però bisogna distinguere per quale hardware stai compilando
il programma: se è per un computer dotato di sistema operativo,
ha senso che il main finisca e restituisca un valore (il controllo
ritorna al sistema operativo, che riceve anche il valore dato
dal programma, che può segnalare la condizione di uscita,
cioè normale o con errore). Se stai compilando il programma
per un microcontrollore e non hai un sistema operativo, a
parte l'aderenza allo standard, non ha senso ne prevedere
un tipo di ritorno, ne uscire dal main! Il programma infatti
in questo caso non dovrebbe mai terminare, ma essere
piuttosto un loop infinito...
A.D.

"A.D." <isd...@libero.ix> ha scritto nel messaggio 
news:afL8j.194348$%k.33...@twister2.libero.it...

E' tutto chiaro ora, ringrazio te e gli altri, per me il problema 
nell'apprendere le cose sta proprio in questi particolari, in questi libri 
si scrivono certe cose ma si danno per scontato argomenti che per chi inizia 
non lo sono affatto, ovviamente vorrei imaprare un po di C per programmare i 
Pic che ora faccio con il Basic 

 qualcosa ma non vede nessun return al suo interno.
I compilatori dei sistemi embedded, di default, hanno un tipo di ritorno 
void. Quindi se si scrive:
main () {
    printf ("hello world\r\n");
}
equivale a scrivere
void main (void) {
    printf ("hello world\r\n");
}
Anche solo per non buttar via inutilmente un byte visto che il binding è 
statico
p.s. printf non credo sia un metodo esistente per i sistemi embedded. Spesso 
si trovano (prototipi):
void sprintf (unsigned char *, const unsigned char *,...);
void fprintf (unsigned short, const unsigned char);
dove il primo è fatto per riempire una stringa mentre il secondo per 
scrivere un carattere su un buffer, tipicamente una UART
Ciao
-- 
____________________
      CG Engineering
 Lab. Ricerca & Sviluppo
********************
Skype : cg_ingegnering
MSN : 
cgaudiola...@interfree.it
ICQ UIN# : 104528066 

 scrivere un carattere su un buffer, tipicamente una UART
In realtà entrambe le funzioni fanno parte della libc ANSI, la prima 
stampa su una stringa, la seconda non su un buffer ma su uno stream.
I prototipi ANSI dovrebbero essere:
int sprintf(char *str, const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
Se chiami la fprintf passandogli come stream l'stdout ottieni lo stesso 
risultato della printf.
Il perchè nei compilatori embedded commerciali facciano sempre le cose 
"quasi" standard ma sempre un po' diverse è un vecchio discorso che 
stavolta evito di ripetere :-)
Ciao

 stavolta evito di ripetere :-)
Infatti il problema è proprio quello. Alla fine però non è detto che sia 
proprio un problema.
Il CCS C (pic) per esempio proprio perchè ha diverse cosette non ANSI, ha un 
sacco di ottimizzazioni che lo rendono in assoluto il più ottimizzato 
compilatore C per pic. C'è da dire che è quasi un linguaggio a sè, ma spesso 
il gioco vale la candela (non è detto che serva assolutamente 
portabilità....)


 portabilità....)
Bhe, devi valutare bene. Queste piccole differenze, proprio perchè sono 
piccole, sono davvero ininfluenti. Sarebbe costato veramente poco, sia 
in termini di lavoro da parte dei produttori del compilatore che in 
termini di ottimizzazione del codice generato, farlo davvero compatibile 
ANSI. La verità è che così sei legato a quel particolare prodotto.
Quindi, sei sicuro di voler/poter usare per tutta la vita lo stesso 
processore/compilatore? Io mi sono risposto di no, per cui la 
portabilità la considero molto importante.
Ciao

 ottimizzazione.
E' piuttosto scorretto, che un compilatore non riporti almeno un
/warning/, sul mancato ritorno da parte di main(), ma appare piuttosto
comune nei compilatori per PIC -- avevo riscontrato la stessa cosa,
valutandone alcuni.
Cambiando target invece si riscontra più spesso l'aderenza allo standard
ISO (ricordo che è lo standard ISO a dettare specifiche più aggiornate
sul linguaggio C, con ISO 9899:1990 e ISO 9899:1999).
La segnalazione di /warning/ è pienamente giustificata dallo standard
ISO, questo richiede infatti che anche main() accetti la ricorsività.
Spesso su compilatori per target piccoli, con una gestione troppo
minimale (o quasi inesistente) dello stack, la ricorsione è scoraggiata
(se non addirittura vietata). Questa caratteristica è sicuramente la
motivazione fondamentale per non richiedere aderenza del compilatore
allo standard per la funzione main(), in aggiunta ad altri limiti anche
al di sotto dei requisiti minimi per l'implementazione "free-standing".
Implementando codice che si dica secondo gli standard ANSI/ISO, ci si
dovrà invece premurare di utilizzare un formato standard anche per main().
~ Lou

 sul linguaggio C, con ISO 9899:1990 e ISO 9899:1999).
Sì, che sono i cosiddetti C89 e C99.
Il punto più grave, secondo me, non è tanto la non conformità del 
prototipo di main, su cui si può certamente soprassedere, ma 
l'affermazione di CG secondo cui, molti compilatori embedded considerano:
foo();
equivalente a
void foo(void);
invece di:
int foo(void);
come vorrebbe lo standard.
Trovo molto più probabile, pensandoci bene, che tali compilatori 
implementino il comportamento corretto in mancanza di una specifica 
indicazione del tipo di ritorno (che quindi sia di default a int), ma 
non segnalino il problema con un warning. Può succedere quindi che molti 
programmatori  dichiarino le loro funzioni senza nessun tipo di ritorno, 
credendo che sia implicitamente void, senza che il compilatore segnali 
nessun problema. Tutto va liscio fino a che non si cambia compilatore, a 
quel punto, il meglio che può succedere è che il codice diventi 
tempestato di warning. Alla luce anche del fatto che in C++ le cose sono 
ancora diverse, se si vuole un minimo di riusabilità del codice, io 
consiglio di specificare *sempre* i parametri di ingresso e quello di 
ritorno, anche e soprattutto se la funzione non prende nulla e non 
ritorna nulla.
Ciao

 ritorna nulla.
Sono quasi interamente d'accordo.
Il "quasi" è per i casi particolari, dove i codice scritto non ha alcun senso
per la portabilità -- un caso era l'applicazione PIC, dove tutto l'algoritmo si
poggiava sull'uso di periferiche interne, di un dispositivo minuscolo.
~ Lou

 qualità) non sia aderente allo standard, ma non l'ho mai usato.
Potrei anche essermi sbagliato, perchè è il compilatore che ho utilizzato 
meno.
Ciao
CG