2012-01-08 26 views
31

In C++, in alcune circostanze tendo ad omettere il nome del parametro. Ma in C, ho ricevuto un errore quando ho omesso il nome del parametro.nome parametro omesso, C++ vs C

Ecco il codice:

void foo(int); //forward-decl, it's OK to omit the parameter's name, in both C++ and C 

int main() 
{ 
    foo(0); 
    return 0; 
} 

void foo(int) //definition in C, it cannot compile with gcc 
{ 
    printf("in foo\n"); 
} 

void foo(int) //definition in C++, it can compile with g++ 
{ 
    cout << "in foo" << endl; 
} 

Perché? Non posso omettere il nome del parametro nella definizione della funzione C?

+2

la scrittura di file di origine multi-lingua è (molto) un duro lavoro. Ti suggerisco di mantenere ogni singolo file sorgente in una sola lingua. – pmg

+0

@ pmg, grazie per il tuo consiglio,:) – Alcott

+0

Ma se vuoi compilare qualcosa in C e C++, non c'è bisogno di scrivere funzioni separate per usare 'printf' e' str :: cout'. 'printf' funziona per entrambe le lingue. Vorrei raccomandare l'utilizzo di due funzioni che possono essere scritte come una sola, a causa della possibilità che la loro funzionalità potrebbe non essere identica. –

risposta

33

No, in C non è possibile omettere gli identificatori per i parametri nelle definizioni di funzione.

Il C99 serie dice:

[6.9.1.5] Se il dichiaratore include un elenco tipo di parametro, la dichiarazione di ogni parametro comprende un identificatore, ad eccezione il caso particolare di un elenco di parametri costituito da un singolo parametro di tipo nullo, nel qual caso non ci deve essere un identificatore. Nessuna lista di dichiarazioni deve seguire.

Il C++ 14 di serie dice:

[8.3.5.11] Un identificatore può opzionalmente essere fornito come parametro nome; se presente in una definizione di funzione, nomina un parametro (talvolta chiamato "argomento formale"). [Nota: In particolare, il parametro nomi sono opzionali nella funzione Principali definizioni e nomi utilizzati per un parametro in diverse dichiarazioni e la definizione di una funzione non deve essere lo stesso.]

+0

Quindi, un nome di variabile è chiamato identificatore? –

+5

@ Mr.TAMER: tutti i nomi di variabili sono identificatori, ma alcuni identificatori non sono nomi di variabili. –

+0

@DietrichEpp: Vedo, grazie :). Con una rapida ricerca ho trovato [questo] (http://msdn.microsoft.com/en-us/library/565w213d.aspx). –

4

È possibile omettere il nome del parametro nella funzione prototipo, ma è necessario dichiararlo nell'implementazione della funzione. Ad esempio, questa compila e funziona bene sotto GCC 4.6.1

void foo(int, int); 

void foo(int value, int secondValue) 
{ 
    printf("In foo with value %d and %d!\n", value, secondValue); 
} 

int main(int argc, char **argv) 
{ 
    foo(10, 15); 
    return 0; 
} 

Uscite: In foo with value 10 and 15!

Per quanto riguarda il motivo per cui (diverso perché gli standard dicono così): C++ permette di chiamare una funzione senza utilizzare tutti gli argomenti, mentre C no. Se non si forniscono tutti gli argomenti a una funzione in C, il compilatore genererà error: too few arguments to function 'foo'

+4

C++ * non * consente di omettere argomenti in una chiamata a meno che i parametri corrispondenti non abbiano valori predefiniti. In questo caso, i valori predefiniti vengono passati implicitamente e la funzione deve fornire nomi per gli argomenti se si riferiscono ai loro valori. La differenza è che ci sono più casi in C++ dove ha senso che una funzione ignori uno dei suoi parametri. –

15

La ragione è che questo è quello che dicono i rispettivi standard linguistici, ma c'è una motivazione per la differenza.

Se non si fornisce un nome per un parametro, la funzione non può fare riferimento a quel parametro.

In C, se una funzione ignora uno dei suoi parametri, di solito ha senso solo per rimuoverla dalla dichiarazione e dalla definizione, e non passarla in nessuna chiamata. Un'eccezione potrebbe essere una funzione di callback, in cui una raccolta di funzioni deve essere tutte dello stesso tipo, ma non tutte utilizzano necessariamente i loro parametri. Ma quello non è uno scenario molto comune.

In C++, se la funzione è derivata da una funzione definita in una classe genitore, deve avere la stessa firma del genitore, anche se la funzione figlio non ha alcuna utilità per uno dei valori dei parametri.

(Si noti che questo non è correlato ai parametri predefiniti, se un parametro in C++ ha un valore predefinito, il chiamante non deve passarlo esplicitamente, ma la definizione della funzione deve ancora fornire un nome se sta per fare riferimento ad esso.)

5

Su un livello puramente pratico, ho a che fare con questo quotidiano. La soluzione migliore fino ad oggi è l'utilizzo del pre-processore. Il mio file di intestazione comune contiene:

//------------------------------------------------------------------------- 
// Suppress nuisance compiler warnings. Yes, each compiler can already 
// do this, each differently! VC9 has its UNREFERENCED_PARAMETER(), 
// which is almost the same as the SUPPRESS_UNUSED_WARNING() below. 
// 
// We append _UNUSED to the variable name, because the dumb gcc compiler 
// doesn't bother to tell you if you erroneously _use_ something flagged 
// with __attribute__((unused)). So we are forced to *mangle* the name. 
//------------------------------------------------------------------------- 
#if defined(__cplusplus) 
#define UNUSED(x)  // = nothing 
#elif defined(__GNUC__) 
#define UNUSED(x)  x##_UNUSED __attribute__((unused)) 
#else 
#define UNUSED(x)  x##_UNUSED 
#endif 

Un esempio dell'uso di UNUSED è:

void foo(int UNUSED(bar)) {} 

A volte è davvero necessario fare riferimento al parametro, ad esempio in un assert() o una dichiarazione di debug. È possibile farlo tramite:

#define USED_UNUSED(x) x##_UNUSED // for assert(), debug, etc 

Inoltre, i seguenti sono utili:

#define UNUSED_FUNCTION(x) inline static x##_UNUSED // "inline" for GCC warning 
#define SUPPRESS_UNUSED_WARNING(x) (void)(x) // cf. MSVC UNREFERENCED_PARAMETER 

Esempi:

UNUSED_FUNCTION(int myFunction)(int myArg) { ...etc... } 

e:

void foo(int bar) { 
#ifdef XXX 
    // ... (some code using bar) 
#else 
    SUPPRESS_UNUSED_WARNING(bar); 
#endif 
} 
+1

Questo è in ritardo di due giorni. Spero che non sia * inutilizzato * ful. –