Sintassi alternativa (K & amp; R) C per la dichiarazione di funzione rispetto ai prototipi
Domanda
Cosa è utile su questa sintassi C
- usando le dichiarazioni di funzione di stile 'K & amp; R'?
int func (p, p2)
void* p;
int p2;
{
return 0;
}
Sono stato in grado di scrivere questo in Visual Studios 2010beta
// yes, the arguments are flipped
void f()
{
void* v = 0;
func(5, v);
}
Non capisco. Qual è il punto di questa sintassi? Posso scrivere:
int func (p, p2)
int p2;
{
return 0;
}
// and write
int func (p, p2)
{
return 0;
}
L'unica cosa che sembra specificare è quanti parametri utilizza e il tipo restituito. Immagino che i parametri senza tipi siano piuttosto interessanti, ma perché permetterlo e int paranName
dopo il dichiaratore di funzione? È strano.
Anche questo è ancora standard C?
Soluzione
La domanda che stai ponendo è in realtà due domande, non una. La maggior parte delle risposte finora ha cercato di coprire il tutto con una coperta generica "questo è lo stile K". risposta, mentre in realtà solo una piccola parte ha qualcosa a che fare con ciò che è noto come stile K & amp; (a meno che tu non veda l'intero linguaggio C come "stile K & amp;" in un modo o nell'altro:)
La prima parte è la strana sintassi usata nella funzione definizione
int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
Questa in realtà è una definizione di funzione in stile K & amp; R. Altre risposte lo hanno trattato abbastanza bene. E non c'è molto da fare, in realtà. La sintassi è obsoleta, ma è ancora pienamente supportata anche in C99 (ad eccezione della regola "nessuna int implicita" in C99, il che significa che in C99 non è possibile omettere la dichiarazione di p2
).
La seconda parte ha poco a che fare con lo stile K & amp; R. Mi riferisco al fatto che la funzione può essere chiamata con " scambiato " argomenti, ovvero nessun controllo del tipo di parametro ha luogo in tale chiamata. Ciò ha ben poco a che fare con la definizione in stile K & amp; R in sé, ma ha tutto a che fare con la tua funzione senza prototipo. Vedi, in C quando dichiari una funzione come questa
int foo();
dichiara effettivamente una funzione foo
che accetta un numero non specificato di parametri di tipo sconosciuto . Puoi chiamarlo come
foo(2, 3);
e come
j = foo(p, -3, "hello world");
ans so on (ottieni l'idea);
Solo la chiamata con argomenti appropriati " funzionerà " (nel senso che gli altri producono comportamenti indefiniti), ma dipende interamente da te assicurarne la correttezza. Il compilatore non è tenuto a diagnosticare quelli errati anche se in qualche modo conosce magicamente i tipi di parametri corretti e il loro numero totale.
In realtà, questo comportamento è una caratteristica del linguaggio C. Una pericolosa, ma una caratteristica comunque. Ti permette di fare qualcosa del genere
void foo(int i);
void bar(char *a, double b);
void baz(void);
int main()
{
void (*fn[])() = { foo, bar, baz };
fn[0](5);
fn[1]("abc", 1.0);
fn[2]();
}
vale a dire. mescolare diversi tipi di funzioni in un "polimorfico" array senza alcun tipo di digitazione (i tipi di funzioni variadiche non possono essere utilizzati qui). Ancora una volta, i pericoli intrinseci di questa tecnica sono abbastanza ovvi (non ricordo di averla mai usata, ma posso immaginare dove può essere utile), ma dopo tutto è C
. Infine, il bit che collega la seconda parte della risposta alla prima. Quando si effettua una definizione di funzione in stile K & amp; R, non viene introdotto un prototipo per la funzione. Per quanto riguarda il tipo di funzione, la tua definizione func
dichiara func
come
int func();
vale a dire. né i tipi né il numero totale di parametri sono dichiarati. Nel tuo post originale dici " ... sembra specificare quanti parametri usa ... " ;. Formalmente parlando, non lo fa! Dopo la tua definizione func
a due parametri K & amp; R puoi ancora chiamare func
come
func(1, 2, 3, 4, "Hi!");
e non vi sarà alcuna violazione dei vincoli. (Normalmente, un compilatore di qualità ti darà un avviso).
Inoltre, un fatto a volte trascurato è quello
int f()
{
return 0;
}
è anche una definizione di funzione in stile K & amp; R che non introduce un prototipo. Per renderlo "moderno" dovresti inserire un void
esplicito nell'elenco dei parametri
int f(void)
{
return 0;
}
Infine, contrariamente a una credenza popolare, sia le definizioni di funzioni in stile K & amp; sia le dichiarazioni di funzioni non prototipate sono pienamente supportate in C99. Il primo è stato deprecato dal C89 / 90, se ricordo bene. C99 richiede che la funzione sia dichiarata prima del primo utilizzo, ma la dichiarazione non deve essere un prototipo. La confusione apparentemente deriva dal popolare miscuglio terminologico: molte persone chiamano qualsiasi dichiarazione di funzione "un prototipo", mentre in realtà "dichiarazione di funzione". non è la stessa cosa di "prototipo".
Altri suggerimenti
Questa è piuttosto vecchia sintassi K & amp; R C (precedente ANSI / ISO C). Al giorno d'oggi, non dovresti più usarlo (come hai già notato il suo principale svantaggio: il compilatore non controllerà i tipi di argomenti per te). Il tipo di argomento per impostazione predefinita è int
nel tuo esempio.
All'epoca, veniva utilizzata questa sintassi, a volte si trovavano funzioni come
foo(p, q)
{
return q + p;
}
che era in realtà una definizione valida, in quanto i tipi di foo
, p
e q
sono predefiniti su int
.
Questa è semplicemente una vecchia sintassi, che precede il "ANSI C" sintassi con cui potresti avere più familiarità. Si chiama " K & amp; RC " ;, in genere.
I compilatori lo supportano per essere completo e per essere in grado di gestire vecchie basi di codice, ovviamente.
Questa è la sintassi K & amp; R originale prima che C fosse standardizzata nel 1989. C89 introdusse prototipi di funzioni, presi in prestito da C ++ e deprecò la sintassi K & amp; R. Non c'è motivo di usarlo (e molti altri motivi per non farlo) nel nuovo codice.
Questa è una reliquia di quando C non aveva prototipi per funzioni. Molto tempo fa, si riteneva che le funzioni (credo) restituissero int
e che tutti i suoi argomenti fossero int
. Non è stato effettuato alcun controllo sui parametri della funzione.
Stai molto meglio usando i prototipi di funzioni nell'attuale linguaggio C.
E devi usarli in C99 (C89 accetta ancora la vecchia sintassi).
E C99 richiede che le funzioni siano dichiarate (possibilmente senza un prototipo). Se stai scrivendo una nuova funzione da zero, devi fornire una dichiarazione ... trasformala anche in un prototipo: non perdi nulla e ottieni ulteriori controlli dal compilatore.