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?

È stato utile?

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 () e copy () . 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 parola    void 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?

C11 N1570 bozza standard

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

C ++ 11 Bozza standard N3337

void f (void) 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.

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