2012-12-21 21 views
5

Si consideri il seguente codice:gcc sta eseguendo le dichiarazioni di funzione implicite in modo non corretto nella modalità c99?

int main (void) { 
    int i = xyzzy(); 
    return i; 
} 
int xyzzy (void) { 
    return 42; 
} 

Ora, anche se il prototipo per xyyzy è sconosciuta al punto di utilizzo, questo funziona in modalità C89, perché il tipo di ritorno di default di una funzione che non ha prototipo è int così la prototipo di funzione implicita e funzione reale sono compatibili.

E, infatti, se si cambia il tipo di ritorno della funzione da float, si ottiene (come previsto):

testprog.c:6: error: conflicting types for 'xyzzy' 
testprog.c:2: error: previous implicit declaration of 'xyzzy' was here 

perché il prototipo implicita e la funzione attuale non è più partita.

Il codice originale compilato con gcc --std=c89 --pedantic -Wall -Wextra mi dà solo l'avvertimento:

testprog.c: In function 'main': 
testprog.c:2: warning: implicit declaration of function 'xyzzy' 

che si prevede, a causa C89 ha questo da dire in 3.7.1 Function definitions:

extern int max (int a, int b) {...}: Qui extern è l'identificatore di classe di archiviazione e int è l'identificatore di tipo (ognuno dei quali può essere omesso in quanto tali sono i valori predefiniti).

e in 3.3.2.2 Function calls:

Se l'espressione che precede la lista degli argomenti tra parentesi in una chiamata di funzione consiste unicamente di un identificatore, e se nessuna dichiarazione è visibile per questo identificatore, l'identificatore è implicitamente dichiarata esattamente come se, nel blocco più interno contenente la chiamata di funzione, la dichiarazione extern int identifier(); apparso.

Quindi l'uso di una funzione prima di dichiarare che sicuramente risultati nel prototipo di default in fase di creazione.


Tuttavia, di queste due frasi sono state rimosse in C99 e noi invece trovare in 6.5.2.2 Function calls (il mio grassetto):

Se l'espressione che indica la funzione chiamata è di tipo puntatore a funzione che restituisce un oggetto digita, l'espressione di chiamata di funzione ha lo stesso tipo di quel tipo di oggetto e ha il valore determinato come specificato in 6.8.6.4. In caso contrario, la chiamata di funzione ha tipo void.

ho capito bene a dire che, se non c'è nessuna dichiarazione in vista quando si tenta di chiamare una funzione, è implicitamente dichiarato con un tipo void ritorno.

Tuttavia, durante la compilazione con gcc --std=c99 --pedantic -Wall -Wextra, viene visualizzato lo stesso avviso relativo alla dichiarazione implicita.

Nel caso in cui C99 non abbia dichiarato implicitamente tale funzione come risposta void?Se lo fosse, mi sarei aspettato un errore previous implicit declaration simile a quello che ho ottenuto quando ho provato a ridichiarlo come restituendo float.

È gcc interrotto qui o mi manca qualcosa nello standard?

+0

compilatore sun/oracle cc con opzione -xc99 e utilizzando float per la funzione restituisce corrente: function (void) return float; precedente: function() che restituisce int: "pax.c", riga 2; Penso che sia difficile che 2 compilatori mostrino la stessa interpretazione errata dello standard, anche se non è impossibile: gli standard dovrebbero evitare un linguaggio che rende difficile capire come dovrebbero essere le cose! – ShinTakezou

+0

@Shin, sembra che anche il compilatore Sun abbia come valore predefinito "return int" anche in modalità C99, nel qual caso potrebbe essere che sto leggendo lo standard in modo errato. Non riuscivo a capire dove. – paxdiablo

+1

Stai leggendo potrebbe non essere corretto; non sarebbe retrocompatibile. In C99, si suppone di avere una dichiarazione (preferibilmente una dichiarazione prototipo) della funzione, o la definizione della funzione, visibile nell'ambito. Nessuna dichiarazione nello scope richiede una diagnostica (e potrebbe fallire la compilazione). Prendo atto che stai citando lo standard ANSI C89 - i numeri di sezione in ISO C90 erano diversi. –

risposta

1

Questo argomento è trattato in una nota ai 6.5.1 espressioni primarie:

2 - Un identificatore è un'espressione primaria, a condizione che è stata dichiarata come designare un oggetto (nel qual caso è un lvalue) o una funzione (nel qual caso è una funzione denominatore ). 79)


79) Pertanto, un identificatore non dichiarato è una violazione della sintassi.

Un'implementazione conforme è richiesto dalla 5.1.1.3 Diagnostics per produrre un messaggio di diagnostica in risposta alla violazione della sintassi di un'espressione chiamata di funzione che coinvolge un identificatore non dichiarato come l'espressione che denota la funzione chiamata. Naturalmente è libero di procedere alla compilazione del programma come se l'identificatore fosse stato dichiarato nello stile implicito - int C89.

Il paragrafo 6.5.2.2p5 deve essere letta con riferimento alla 6.5.2.2p1 vincolo:

1 - L'espressione che indica la funzione chiamata ha tipo puntatore a funzionare ritorno void o restituire un tipo di oggetto diverso da un tipo di matrice.

Quindi, se il "espressione che indica la funzione chiamata" fa non hanno tipo "puntatore di funzionare restituendo un tipo di oggetto", si deve ipso facto (dal vincolo 6.5. 2.2p1) digitare "puntatore alla funzione che restituisce void", ed è questo il caso che "Altrimenti" nelle copertine 6.5.2.2p5. Cioè, con il mio inserimento in [parentesi quadre]:

5 - Se l'espressione che indica la funzione chiamata ha tipo puntatore a funzione che restituisce un tipo di oggetto, l'espressione di funzione chiamata ha lo stesso tipo di quello tipo di oggetto e ha il valore determinato come specificato in 6.8.6.4. Altrimenti, [vale a dire se l'espressione che denota la funzione chiamata ha il tipo puntatore alla funzione che restituisce void,] la chiamata di funzione ha tipo void.

Questo è un caso di linguaggio speciale richiesto per void in contrapposizione a tipi di oggetto; non è una licenza per l'espressione della funzione chiamata che deve essere o contenere un identificatore non dichiarato.

4

Stai leggendo lo standard in modo errato. Non esiste una dichiarazione di funzione implicita in C. Viene rimossa dalla lingua da C99.

GCC emette un avviso quando vede un costrutto errato simile a una dichiarazione di funzione implicita. Questo è OK per quanto riguarda lo standard. Lo standard richiede una diagnostica qui e un avvertimento è una diagnostica. È possibile utilizzare il flag -Werror=implicit-function-declaration in GCC per trasformare questo in un errore.

+0

Non ero in realtà dopo un'asserzione non supportata, posso ottenerli ovunque :-) Puoi indicare la parte dello standard che lo afferma, e come si concilia con la citazione di 6.5.2.2? – paxdiablo

+0

Lo standard di per sé non dice molto sulle cose che non sono nella lingua. È possibile trovare alcuni riferimenti nella letteratura circostante, come le bozze di commissione. Penso che sia anche nella prefazione dello standard attuale, ma non ne sono troppo sicuro. 6.5.2.2 riguarda il derivare il tipo di un'espressione di chiamata dal tipo di funzione e non menziona le dichiarazioni ovunque. –