è f (nulla) deprecato in C e C ++ moderni [duplicato]
-
03-07-2019 - |
Domanda
Questa domanda ha già una risposta qui:
Attualmente sto eseguendo il refactoring / riordino del vecchio codice C utilizzato in un progetto C ++ e vedo regolarmente funzioni come:
int f(void)
che tenderei a scrivere come:
int f()
C'è qualche motivo per non sostituire (void) con () in tutta la base di codice per migliorare la coerenza, o c'è una sottile differenza tra i due di cui non sono a conoscenza? Più specificamente, se una funzione membro virtuale in C ++ è descritta come:
virtual int f(void)
e una classe derivata include una funzione membro:
<*>è una sostituzione valida? Inoltre, potrei riscontrare problemi con i linker basati su firme quasi identiche?
Soluzione
In C, la dichiarazione int f (void)
indica una funzione che restituisce int che non accetta parametri. La dichiarazione int f ()
indica una funzione che restituisce int che accetta un numero qualsiasi di parametri. Pertanto, se si dispone di una funzione che non accetta parametri in C, il primo è il prototipo corretto.
In C ++, credo che int f (void)
sia deprecato e int f ()
è preferito, in quanto significa specificamente una funzione che non accetta parametri.
Altri suggerimenti
Per aggiungere alla risposta di Chris, usare int f ()
è una cattiva pratica in C, secondo la mia esperienza, poiché perdi la capacità del compilatore di confrontare la dichiarazione della funzione con la sua definizione, per assicurarti che verrà chiamato correttamente.
Ad esempio, il codice seguente è conforme agli standard C:
#include <stdio.h>
void foo();
void bar(void) {
foo();
}
void foo(int a) {
printf("%d\n", a);
}
Ma comporta un comportamento indefinito, poiché a
non è stato passato a foo
.
In C ++, ci sono due versioni di foo
: una che non accetta argomenti e una che accetta un int
. Quindi bar
finisce per chiamare la versione non definita, il che comporterebbe un errore del linker (supponendo che non ci siano altre definizioni di foo
)
Le risposte sopra sono abbastanza corrette, ma sto collegando all'eccellente pagina di David Tribble in quanto fornisce un grande spiegazione su questo e su molti altri argomenti.
I punti salienti:
C distingue tra una funzione dichiarato con un elenco di parametri vuoto e una funzione dichiarata con a elenco di parametri composto solo da vuoto. Il primo è un non prototipo funzione che accetta un numero non specificato di argomenti, mentre quest'ultimo è a funzione prototipata prendendo n argomenti.
C ++, d'altra parte, fa no distinzione tra i due dichiarazioni e le considera entrambe per indicare una funzione che prende n argomenti.
Per il codice che si intende essere compilato come C o C ++, il migliore la soluzione a questo problema è sempre dichiarare le funzioni senza parametri con un prototipo di vuoto esplicito.
I prototipi di funzioni vuote sono a caratteristica obsoleta in C99 (come loro erano in C89).
Modifica: dopo aver esaminato lo standard, forse vale la pena notare che la sintassi func (nulla) è non deprecata in C ++, ma è comunemente considerata più un linguaggio di tipo C. Penso che la maggior parte dei programmatori C ++ che ho incontrato preferiscano l'elenco di parametri vuoto.
Modifica 2: aggiunta di un preventivo dallo standard C ++, sezione 8.3.5, paragrafo 2:
" Se la clausola-parametro-dichiarazione è vuota, la funzione non accetta argomenti. L'elenco dei parametri (vuoto) equivale all'elenco dei parametri vuoto. Tranne questo caso speciale, void non deve essere un tipo di parametro (sebbene i tipi derivati ??da void, come void *, can). & Quot;
Non si fa menzione del fatto che entrambi i moduli sono obsoleti. Grazie ancora all'eccellente sito Web di Mr. Tribble per avermi indicato la sezione corretta dello standard.
tl; dr: usa void
.
Data la compatibilità con le versioni precedenti in C ++ e il poco di ambiguità identificato di seguito, asserisco che torniamo indietro a KnR e ANSI C per una risposta conclusiva:
int getline(void);
int copy(void)
Poiché le versioni specializzate di getline e copy non hanno argomenti, la logica suggerirebbe che i loro prototipi all'inizio del file dovrebbe essere
getline ()
ecopy ()
. Ma per compatibilità con programmi C precedenti lo standard prende un elenco vuoto come vecchio stile dichiarazione e disattiva il controllo di tutti gli argomenti; la parolavoid
deve essere utilizzato per un elenco esplicitamente vuoto. [Kernighan & amp; Richie, il linguaggio di programmazione C, 1988, Pg 32-33]
e ..
Il significato speciale dell'elenco di argomenti vuoto è destinato a consentire vecchi programmi C da compilare con nuovi compilatori. Ma è una cattiva idea usalo con nuovi programmi. Se la funzione accetta argomenti, dichiarare loro; se non accetta argomenti, usa void [ibid, Pg. 73]
EDIT: ha suddiviso il resto in una discussione separata qui: Specificare l'uso del vuoto nella dichiarazione di una funzione che non accetta argomenti risolve The Most Vexing Parse?
void f ()
è obsoleto, void f (void)
consigliato:
6.11.6 Dichiaratori di funzioni :
1 L'uso di dichiaratori di funzioni con parentesi vuote (non parametro di formato prototipo dichiaratori di tipo) è una caratteristica obsoleta.
Introduzione :
2 Alcune funzionalità sono obsolete, il che significa che possono essere prese in considerazione ritiro in future revisioni di questo standard internazionale. Sono conservati perché del loro uso diffuso, ma del loro uso in nuove implementazioni (per l'implementazione funzionalità) o nuovi programmi (per la lingua [6.11] o funzionalità della libreria [7.31]) sono sconsigliati.
Discussione dettagliata: https://stackoverflow.com/a/36292431/895245
Né void f (void)
né void f ()
sono obsoleti.
void f (void)
esiste per compatibilità con C. Allegato C "Compatibilità" C.1.7 Clausola 8: dichiaratori :
8.3.5 Modifica: in C ++, una funzione dichiarata con un elenco di parametri vuoto non accetta argomenti. In C, un vuoto elenco parametri significa che il numero e il tipo degli argomenti della funzione sono sconosciuti.
Poiché void f ()
è deprecato in C e void f (void)
consigliato, void f (void)
esiste per purché C ++ desideri mantenere la compatibilità.
void f (void)
e void f ()
sono gli stessi in C ++. Quindi il void f (void)
più lungo ha senso solo se ti interessa scrivere codice compilabile in C e C ++, che probabilmente non ne vale la pena.
Discussione dettagliata: https://stackoverflow.com/a/36835303/895245
In C ++, int f (void)
è in effetti una dichiarazione deprecata che è equivalente al 100% a int f ()
. è la stessa firma. Il vuoto
in questo contesto è significativo come ad es. spazi bianchi. Ciò significa anche che sono soggetti alla One Definition Rule (non sovraccaricano) e Derived :: f (void)
sovrascrive Base :: f ()
.
Non scherzare con cose come f (const void)
, comunque. Non c'è molto consenso sul significato di quel tipo di stranezza.