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?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top