Cosa significa void in C, C ++ e C #?


170

Cercando di ottenere i fondamenti su da dove viene il termine " vuoto " e perché si chiama vuoto. L'intenzione della domanda è di aiutare qualcuno che non ha esperienza in C, e improvvisamente sta guardando una base di codice basata su C.


2
Questa domanda mescola 3 lingue ... quella domanda legacy dovrebbe essere divisa in 3 domande diverse.
Stargateur

Risposte:


225

Fondamentalmente significa "niente" o "nessun tipo"

Esistono 3 modi base per usare il vuoto:

  1. Argomento int myFunc(void) della funzione : - la funzione non accetta nulla.

  2. Valore restituito void myFunc(int) dalla funzione : - la funzione non restituisce nulla

  3. Puntatore di dati generico: void* data - 'dati' è un puntatore a dati di tipo sconosciuto e non può essere differito

Nota: l' voidin un argomento di funzione è opzionale in C ++, quindi int myFunc()è esattamente la stessa int myFunc(void), e si lascia completamente in C #. È sempre richiesto per un valore di ritorno.


7
vuoto nella lista degli argomenti è opzionale in C ++, vedere stackoverflow.com/questions/416345/...
Daniel Earwicker

1
Userei "nessun tipo" anziché "nessuna dimensione"
Kjetil Joergensen il

@Earwicker e kjetijor, entrambi i punti positivi su cui ho discusso, ma la mia mente insonne aveva bisogno di aiuto;) Grazie.
Gerald,

9
Non in disaccordo, ma un ulteriore uso del vuoto è nel trucco "cast to void" per sopprimere gli avvertimenti per valori inutilizzati. È un po 'allungato poiché in realtà non corrisponde a come il compilatore interpreta le cose, ma puoi interpretarlo nel senso che "sto usando questo valore per non fare nulla".
Steve Jessop,

22
In C ++, void nell'elenco degli argomenti è facoltativo. Tuttavia, in C, NON è facoltativo: foo () significa che accetta un numero qualsiasi di parametri di qualsiasi tipo, mentre foo (vuoto) significa che accetta zero parametri.
Adam Rosenfield,

33

L'ho sempre considerato assente . Ecco quattro casi in linguaggio C che corrispondono a questo uso di assenti

  • R f(void)- I parametri di funzione sono assenti
  • void f(P)- Il valore di ritorno è assente
  • void *p- Il tipo di ciò che viene indicato è assente
  • (void) p- L'uso del valore è assente

Altri discendenti del C lo usano per altre cose. Il Dlinguaggio di programmazione lo utilizza per i casi in cui un inizializzatore è assente

  • T t = void;- il valore di inizializzazione è assente

4
Cosa fa (void)p? Non ho capito bene cosa intendevi per "utilizzo del valore assente".
Yashas,

@Yashas Se anche qualcuno è confuso sull'affermazione (void) var;, ho trovato risposte dettagliate su stackoverflow.com/q/21045615 .
Arnie97,

14

Esistono due modi per utilizzare void:

void foo(void);

o

void *bar(void*);

Il primo indica che non viene passato alcun argomento o che non viene restituito alcun argomento.

Il secondo dice al compilatore che non esiste alcun tipo associato ai dati, il che significa che non è possibile utilizzare i dati a cui punta fino a quando non viene trasmesso a un tipo noto.

Ad esempio, vedrai molto void*usato quando hai un'interfaccia che chiama una funzione i cui parametri non possono essere conosciuti in anticipo.

Ad esempio, nel kernel Linux durante il differimento del lavoro imposterai una funzione da eseguire in un secondo momento dandogli un puntatore alla funzione da eseguire e un puntatore ai dati da passare alla funzione:

struct _deferred_work {
sruct list_head mylist;
.worker_func = bar;
.data        = somedata;
} deferred_work;

Quindi un thread del kernel passa sopra un elenco di lavori differiti e quando arriva a questo nodo esegue efficacemente:

bar(somedata);

Quindi nel bar hai:

void bar(void* mydata) {
    int *data = mydata;
    /* do something with data */;
}

13

Significa "nessun valore". Si utilizza voidper indicare che una funzione non restituisce un valore o che non ha parametri o entrambi. Abbastanza coerente con gli usi tipici della parola void in inglese.


4

Indica l'assenza di un valore di ritorno in una funzione.

Alcune lingue hanno due tipi di subroutine: procedure e funzioni. Le procedure sono solo una sequenza di operazioni, mentre una funzione è una sequenza di operazioni che restituisce un risultato.

In C e suoi derivati, la differenza tra i due non è esplicita. Tutto è sostanzialmente una funzione. la voidparola chiave indica che non è una funzione "effettiva", poiché non restituisce un valore.


3

Pensa al vuoto come alla "struttura vuota". Lasciatemi spiegare.

Ogni funzione accetta una sequenza di parametri, in cui ogni parametro ha un tipo. In effetti, potremmo impacchettare i parametri in una struttura, con gli slot della struttura corrispondenti ai parametri. Questo rende ogni funzione ha esattamente un argomento. Allo stesso modo, le funzioni producono un risultato, che ha un tipo. Potrebbe essere un valore booleano, oppure potrebbe essere float, oppure potrebbe essere una struttura, contenente un insieme arbitrario di altri valori tipizzati. Se vogliamo un linguaggio che abbia più valori di ritorno, è facile insistere sul fatto che siano impacchettati in una struttura. In effetti, potremmo sempre insistere sul fatto che una funzione ha restituito una struttura. Ora ogni funzione accetta esattamente un argomento e produce esattamente un valore.

Ora, cosa succede quando ho bisogno di una funzione che produce un valore "no"? Bene, considera cosa ottengo quando creo una struttura con 3 slot: contiene 3 valori. Quando ho 2 slot, contiene due valori. Quando ha uno slot, un valore. E quando ha zero slot, contiene ... uh, zero valori o "nessun" valore ". Quindi, posso pensare a una funzione che restituisce il vuoto come restituire una struttura che non contiene valori. Puoi persino decidere che" vuoto " è solo un sinonimo del tipo rappresentato dalla struttura vuota, piuttosto che una parola chiave nella lingua (forse è solo un tipo predefinito :)

Allo stesso modo, posso pensare a una funzione che non richiede valori come accettare una struttura vuota, ad esempio "vuoto".

Posso persino implementare il mio linguaggio di programmazione in questo modo. Passare un valore vuoto occupa zero byte, quindi passare valori vuoti è solo un caso speciale di passaggio di altri valori di dimensioni arbitrarie. Ciò semplifica al compilatore il trattamento del risultato o dell'argomento "vuoto". Probabilmente si desidera una funzione di lingua che può eliminare un risultato di funzione; in C, se chiamate la funzione risultato non nulla foo nella seguente istruzione: foo (...); il compilatore sa che foo produce un risultato e semplicemente lo ignora. Se void è un valore, questo funziona perfettamente e ora le "procedure" (che sono solo un aggettivo per una funzione con risultato vuoto) sono solo banali casi speciali di funzioni generali.

Void * è un po 'più divertente. Non penso che i designer C abbiano pensato al vuoto nel modo sopra; hanno appena creato una parola chiave. Quella parola chiave era disponibile quando qualcuno aveva bisogno di un punto a un tipo arbitrario, quindi annulla * come il linguaggio in C. Funziona piuttosto bene se interpreti il ​​vuoto come una struttura vuota. Un puntatore void * è l'indirizzo di un luogo in cui è stata posizionata quella struttura vuota.

Lancia da void * a T * per altri tipi T, risolvendo anche questa prospettiva. I lanci di puntatori sono un trucco completo che funziona sulle architetture più comuni per trarre vantaggio dal fatto che se un composto di tipo T ha un elemento con sottotipo S posizionato fisicamente all'inizio di T nel suo layout di archiviazione, quindi getta S * in T * e viceversa l'utilizzo dello stesso indirizzo fisico della macchina tende a risolversi, poiché la maggior parte dei puntatori di macchine ha una singola rappresentazione. Sostituendo il tipo S con il tipo void si ottiene esattamente lo stesso effetto, e quindi si esegue il casting su / da void *.

Il linguaggio di programmazione PARLANSE implementa le idee sopra abbastanza da vicino. Abbiamo preso in giro il suo design e non abbiamo prestato molta attenzione al "vuoto" come tipo di ritorno e quindi abbiamo parole chiave linguistiche per la procedura. È principalmente solo una semplice modifica della sintassi, ma è una delle cose a cui non ti aggiri una volta ottenuto un codice di lavoro di grandi dimensioni in una lingua.



2

Tre casi d'uso per nulla:

  1. Firme delle funzioni. void foo(int bar)non restituisce un valore. int bar(void)non prende alcun parametro, ma questo è di solito espressa con lista di argomenti vuota: int bar(). L'uso della parola chiave void qui corrisponde al suo significato in inglese.

  2. Puntatore di tipo top generico void *che punta a dati non specificati e non può essere rinviato. Qui il significato di vuoto è diverso dagli altri significati di vuoto: tipo universale contro nessun tipo.

  3. In cast come (void) new Foo(this)per indicare che il valore di ritorno viene deliberatamente gettato via. Qui l'utilizzo della parola chiave corrisponde anche al suo significato in inglese.

I casi 1 e 2 erano già coperti da @Gerald ma il caso 3 non è stato ancora affrontato.


2

Se stai spiegando il concetto a un principiante, potrebbe essere utile usare un'analogia. L'uso del vuoto in tutti questi casi ha un significato analogo a una pagina di un libro che ha le seguenti parole: "Questa pagina è stata lasciata intenzionalmente vuota". Serve a differenziare il compilatore tra qualcosa che dovrebbe essere contrassegnato come errore, rispetto a un tipo che deve essere lasciato intenzionalmente in bianco perché è il comportamento desiderato.

Appare sempre nel codice in cui normalmente ti aspetteresti di visualizzare un tipo, ad esempio un tipo restituito o un tipo di puntatore. Questo è il motivo per cui in C #, il vuoto viene mappato su un tipo CLR effettivo, System.Void perché è un tipo in sé.

Alcuni linguaggi di programmazione non hanno mai sviluppato il concetto di vuoto, proprio come alcune culture umane non hanno mai inventato il concetto del numero zero. Void rappresenta lo stesso progresso in un linguaggio di programmazione come il concetto di zero rappresenta per il linguaggio umano.


Solo una nota per quanto riguarda la tua ultima frase - tieni presente che è vero solo per le lingue tipizzate staticamente. Le lingue tipizzate dinamicamente non hanno bisogno di nulla poiché i loro metodi potrebbero semplicemente non restituire nulla - il "vuoto" è implicito dalla mancanza di qualcos'altro che viene restituito.
Mark Embling,

Correzione al mio ultimo commento - intendevo dire l'ultimo paragrafo (non la frase).
Mark Embling,

1

Significa "nessun valore". Usa void per indicare che una funzione non restituisce un valore o che non ha parametri o entrambi. È molto coerente con gli usi tipici della parola void in inglese.

Void non deve essere confuso con null. Null significa per la variabile il cui indirizzo è nello stack, il valore sull'heap per quell'indirizzo è vuoto.


0

Void viene utilizzato solo nelle firme del metodo. Per i tipi restituiti significa che il metodo non restituirà nulla al codice chiamante. Per i parametri significa che nessun parametro viene passato al metodo

per esempio

void MethodThatReturnsAndTakesVoid(void)
{
// Method body
}

In C # possiamo omettere il vuoto per i parametri e possiamo scrivere il codice sopra come:

void MethodThatReturnsAndTakesVoid()
{
// Method body
}

Void non deve essere confuso con null. Null significa per la variabile il cui indirizzo è nello stack, il valore sull'heap per quell'indirizzo è vuoto.


0

Void è un tipo incompleto che, per definizione, non può essere un valore. Ciò significa che non è possibile assegnare un valore.

Quindi non può contenere alcun valore.


-1

void indica che non verrà restituito alcun valore dalla funzione o dal metodo


-1

Vuoto significa che non è necessario alcun valore nel tipo restituito da una funzione in tutte e tre le lingue.


-1

Void è l'equivalente del Sub di Visual Basic.


Solo come tipo di ritorno. Posso pensare ad altri tre usi di void: argomenti void (la funzione non accetta nulla), puntatori void (nessun tipo di puntatore specificato) e cast void (valore di scarto).
c4757p,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.