Cosa vuol dire vuoto in C, C ++ e C #?

Cercando di ottenere i fondamenti su dove il termine ” vuoto ” deriva e perché è chiamato vuoto. L’intenzione della domanda è di assistere qualcuno che non ha esperienza in C, e improvvisamente sta guardando un codice base basato su C.

Fondamentalmente significa “niente” o “nessun tipo”

Ci sono 3 modi fondamentali in cui viene utilizzato il vuoto:

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

  2. Funzione valore restituito: void myFunc(int) – la funzione non restituisce nulla

  3. Puntatore dati generici: void* data – ‘data’ è un puntatore a dati di tipo sconosciuto e non può essere dereferenziato

Nota: il void in un argomento di funzione è facoltativo in C ++, quindi int myFunc() è esattamente lo stesso di int myFunc(void) , e viene lasciato completamente in C #. È sempre richiesto per un valore di ritorno.

L’ho sempre interpretato come assente . Qui ci sono quattro casi nel linguaggio C che corrisponde a questo uso di assente

  • R f(void) – I parametri di funzione sono assenti
  • void f(P) – Il valore di ritorno è assente
  • void *p – Il tipo di cosa è indicato è assente
  • (void) p – L’uso del valore è assente

Altri discendenti di C lo usano per altre cose. Il linguaggio di programmazione D lo usa per i casi in cui un inizializzatore è assente

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

Significa “senza valore”. Si utilizza void per indicare che una funzione non restituisce un valore o che non ha parametri o entrambi. Piuttosto coerente con gli usi tipici del vuoto parola in inglese.

Esistono due modi per utilizzare il vuoto:

 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 un tipo associato ai dati che significhi effettivamente che non è ansible utilizzare i dati puntati fino a quando non viene lanciato su un tipo noto.

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

Ad esempio, nel Linux Kernel quando si rimanda il lavoro, si configurerà 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 su un elenco di lavoro posticipato e quando arriva a questo nodo viene effettivamente eseguito:

 bar(somedata); 

Poi nel bar hai:

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

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 restituiscono un risultato.

In C e derivati, la differenza tra i due non è esplicita. Tutto è fondamentalmente una funzione. la parola chiave void indica che non è una funzione “effettiva”, poiché non restituisce un valore.

Pensa al vuoto come alla “struttura vuota”. Lasciatemi spiegare.

Ogni funzione prende 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 fa sì che ogni funzione abbia esattamente un argomento. Allo stesso modo, le funzioni producono un risultato, che ha un tipo. Potrebbe essere un booleano, o potrebbe essere float, oppure potrebbe essere una struttura, contenente un insieme arbitrario di altri valori digitati. Se vogliamo un languge che ha più valori di ritorno, è facile semplicemente insistere per essere impacchettati in una struttura. In effetti, potremmo sempre insistere sul fatto che una funzione abbia restituito una struttura. Ora ogni funzione richiede esattamente un argomento e produce esattamente un valore.

Ora, cosa succede quando ho bisogno di una funzione che produce valore “no”? Bene, considera quello che 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, detiene … uh, zero values ​​o “no” value. Quindi, posso pensare a una funzione che restituisce null come restituire una struct che non contiene valori. Puoi persino decidere che “void” è solo un sinonimo per il 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. Il passaggio di un valore void richiede zero byte, quindi il passaggio di valori void è solo un caso speciale di passaggio di altri valori di dimensione arbitraria. Questo rende facile per il compilatore trattare il risultato o l’argomento “vuoto”. Probabilmente vorresti una funzionalità linguistica che possa allontanare un risultato di funzione; in C, se chiami la funzione di risultato non vuoto pippo nella seguente frase: foo (…); il compilatore sa che foo produce un risultato e semplicemente lo ignora. Se il vuoto è un valore, questo funziona perfettamente e ora le “procedure” (che sono solo un aggettivo per una funzione con risultato nullo) sono solo casi speciali banali di funzioni generali.

Void * è un po ‘più divertente. Non penso che i progettisti di C pensassero al vuoto nel modo sopraindicato; hanno appena creato una parola chiave. Quella parola chiave era disponibile quando qualcuno aveva bisogno di un punto per un tipo arbitrario, quindi vuoto * come l’idioma in C. In realtà funziona piuttosto bene se interpretate il vuoto come una struttura vuota. Un puntatore void * è l’indirizzo di un luogo in cui è stata inserita la struttura vuota.

I lanci da vuoto * a T * per altri tipi T, funzionano anche in questa prospettiva. I cast di puntatori sono un cheat 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 memoria, quindi trasmette S * a T * e viceversa, usando lo stesso indirizzo fisico della macchina tende a funzionare, poiché la maggior parte dei puntatori di macchine ha una singola rappresentazione. Sostituire il tipo S con il tipo void dà esattamente lo stesso effetto, e quindi il cast da / a void * funziona.

Il linguaggio di programmazione PARLANSE implementa le idee di cui sopra con molta attenzione. Abbiamo fallito nel suo design e non abbiamo prestato molta attenzione al “vuoto” come tipo di ritorno e quindi abbiamo parole chiave per la procedura. Si tratta principalmente di un semplice cambiamento di syntax, ma è una delle cose che non si ottiene quando si ottiene un codice funzionante di grandi dimensioni in una lingua.

In c # si usa la parola chiave void per indicare che un metodo non restituisce un valore:

 public void DoSomeWork() { //some work } 

Tre casi d’uso per il vuoto:

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

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

  3. In casts come (void) new Foo(this) per significare che il valore di ritorno è 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 risolto.

Se stai spiegando il concetto a un principiante, potrebbe essere utile usare un’analogia. L’uso del vuoto in tutti questi casi è analogo al significato di una pagina in un libro con le seguenti parole: “Questa pagina è stata lasciata intenzionalmente vuota”. È per differenziare il compilatore tra qualcosa che dovrebbe essere contrassegnato come un errore, rispetto a un tipo che è intenzionalmente lasciato in bianco perché questo è il comportamento che si desidera.

Appare sempre nel codice dove normalmente ti aspetteresti di vedere apparire un tipo, come un tipo di ritorno o un tipo di puntatore. Questo è il motivo per cui in C #, void mappa 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. Il vuoto rappresenta lo stesso progresso in un linguaggio di programmazione poiché il concetto di zero rappresenta il linguaggio umano.

Significa “senza valore”. Usa vuoto 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 è in stack, il valore sull’heap per quell’indirizzo è vuoto.

Il vuoto viene utilizzato solo nelle firme dei metodi. Per i tipi di ritorno significa che il metodo non restituirà nulla al codice chiamante. Per i parametri significa, nessun parametro è 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 è in stack, il valore sull’heap per quell’indirizzo è vuoto.

Il vuoto è un tipo incompleto che per definizione non può essere un lvalue. Cosa significa che non può essere assegnato un valore.

Quindi non può contenere alcun valore.

vuoto significa che non restituirai alcun valore dalla funzione o dal metodo

Vuoto significa nessun valore richiesto nel tipo restituito da una funzione in tutte e tre le lingue.

Void è l’equivalente di Sub di Visual Basic.