Chcielibyśmy poznać podstawy dotyczące tego, skąd pochodzi termin „ pustka ” i dlaczego nazywa się go pustką. Celem pytania jest pomoc komuś, kto nie ma doświadczenia w C i nagle szuka kodu opartego na C.
Chcielibyśmy poznać podstawy dotyczące tego, skąd pochodzi termin „ pustka ” i dlaczego nazywa się go pustką. Celem pytania jest pomoc komuś, kto nie ma doświadczenia w C i nagle szuka kodu opartego na C.
Odpowiedzi:
Zasadniczo oznacza „nic” lub „brak typu”
Istnieją 3 podstawowe sposoby wykorzystania void:
Argument funkcji: int myFunc(void)
- funkcja nic nie pobiera.
Wartość zwracana funkcji: void myFunc(int)
- funkcja nic nie zwraca
Ogólny wskaźnik danych: void* data
- „dane” to wskaźnik do danych nieznanego typu, którego nie można wyłuskać
Uwaga: void
argument in a function jest opcjonalny w C ++, więc int myFunc()
jest dokładnie taki sam jak int myFunc(void)
i jest całkowicie pomijany w C #. Jest to zawsze wymagane dla wartości zwracanej.
Zawsze uważałem, że oznacza nieobecność . Oto cztery przypadki w języku C, które pasują do tego zastosowania nieobecności
R f(void)
- parametry funkcyjne są nieobecnevoid f(P)
- Brak wartości zwracanejvoid *p
- Rodzaj co jest wskazywany jest nieobecny(void) p
- Wykorzystanie wartości jest nieobecnyInni potomkowie C używają go do innych celów. Język D
programowania używa go w przypadkach, gdy nie ma inicjatora
T t = void;
- brak wartości inicjalizacyjnej(void)p
? Nie do końca rozumiem, co masz na myśli, mówiąc „brak użycia wartości”.
(void) var;
stwierdzenia, szczegółowe odpowiedzi znalazłem na stackoverflow.com/q/21045615 .
Istnieją dwa sposoby korzystania z void:
void foo(void);
lub
void *bar(void*);
Pierwsza wskazuje, że żaden argument nie jest przekazywany lub nie jest zwracany żaden argument.
Druga mówi kompilatorowi, że nie ma typu związanego z danymi, co oznacza, że nie można użyć wskazanych danych, dopóki nie zostaną one rzutowane na znany typ.
Na przykład zobaczysz void*
często używane, gdy masz interfejs, który wywołuje funkcję, której parametry nie mogą być znane z wyprzedzeniem.
Na przykład w jądrze Linuksa podczas odroczenia pracy skonfigurujesz funkcję do uruchomienia w późniejszym czasie, dając jej wskaźnik do funkcji, która ma być uruchomiona i wskaźnik do danych, które mają być przekazane do funkcji:
struct _deferred_work {
sruct list_head mylist;
.worker_func = bar;
.data = somedata;
} deferred_work;
Następnie wątek jądra przegląda listę odroczonej pracy i kiedy dotrze do tego węzła, skutecznie wykonuje:
bar(somedata);
W barze masz:
void bar(void* mydata) {
int *data = mydata;
/* do something with data */;
}
Wskazuje na brak wartości zwracanej w funkcji.
Niektóre języki mają dwa rodzaje podprogramów: procedury i funkcje. Procedury to tylko sekwencja operacji, podczas gdy funkcja to sekwencja operacji, które zwracają wynik.
W C i jego pochodnych różnica między nimi nie jest wyraźna. W zasadzie wszystko jest funkcją. void
słów kluczowych wskazuje, że to nie jest „rzeczywisty” funkcja, ponieważ nie zwraca wartości.
Pomyśl o pustce jako o „pustej strukturze”. Pozwól mi wyjaśnić.
Każda funkcja przyjmuje sekwencję parametrów, przy czym każdy parametr ma typ. W rzeczywistości moglibyśmy spakować parametry w strukturę, w której szczeliny struktury odpowiadają parametrom. To sprawia, że każda funkcja ma dokładnie jeden argument. Podobnie funkcje dają wynik, który ma typ. Może to być wartość logiczna, zmiennoprzecinkowa lub struktura zawierająca dowolny zestaw innych wpisanych wartości. Jeśli chcemy języka, który ma wiele zwracanych wartości, łatwo jest po prostu nalegać, aby były one spakowane w strukturę. W rzeczywistości zawsze moglibyśmy nalegać, aby funkcja zwracała strukturę. Teraz każda funkcja przyjmuje dokładnie jeden argument i generuje dokładnie jedną wartość.
Co się dzieje, gdy potrzebuję funkcji, która generuje wartość „nie”? Cóż, zastanów się, co otrzymuję, gdy utworzę strukturę z 3 gniazdami: zawiera 3 wartości. Kiedy mam 2 gniazda, ma dwie wartości. Gdy ma jeden slot, jedną wartość. A kiedy ma zerowe szczeliny, przechowuje ... uh, zerowe wartości lub „brak”. Tak więc mogę myśleć o funkcji zwracającej void jako zwracającej strukturę nie zawierającą wartości. Możesz nawet zdecydować, że „void” jest tylko synonimem typu reprezentowanego przez pustą strukturę, a nie słowem kluczowym w języku (może to tylko predefiniowany typ :)
Podobnie, mogę myśleć o funkcji nie wymagającej wartości jako akceptującej pustą strukturę, np. „Void”.
Mogę nawet w ten sposób zaimplementować swój język programowania. Przekazanie wartości void zajmuje zero bajtów, więc przekazywanie wartości void jest tylko specjalnym przypadkiem przekazywania innych wartości o dowolnym rozmiarze. Ułatwia to kompilatorowi traktowanie wyniku lub argumentu „void”. Prawdopodobnie potrzebujesz funkcji langauge, która może odrzucać wynik funkcji; w C, jeśli wywołasz funkcję wynikową nieważną foo w następującej instrukcji: foo (...); kompilator wie, że foo daje wynik i po prostu go ignoruje. Jeśli void jest wartością, działa to doskonale, a teraz „procedury” (które są po prostu przymiotnikiem funkcji z wynikiem void) są po prostu trywialnymi przypadkami specjalnymi funkcji ogólnych.
Void * jest trochę zabawniejszy. Nie sądzę, by projektanci C myśleli o pustce w powyższy sposób; po prostu utworzyli słowo kluczowe. To słowo kluczowe było dostępne, gdy ktoś potrzebował punktu do dowolnego typu, a więc void * jako idiom w C. W rzeczywistości działa całkiem dobrze, jeśli interpretujesz void jako pustą strukturę. Wskaźnik void * to adres miejsca, w którym została umieszczona ta pusta struktura.
Rzuty z pustki * na T * dla innych typów T również sprawdzają się z tą perspektywą. Rzuty wskaźników są kompletnym oszustwem, które działają na większości popularnych architektur, aby wykorzystać fakt, że jeśli związek typu T ma element z podtypem S umieszczony fizycznie na początku T w układzie pamięci, to rzutowanie S * na T * i odwrotnie, użycie tego samego adresu fizycznego maszyny zwykle się sprawdza, ponieważ większość wskaźników maszynowych ma jedną reprezentację. Zastąpienie typu S typem void daje dokładnie ten sam efekt, a więc rzucanie do / z void * działa.
Język programowania PARLANSE dość ściśle realizuje powyższe pomysły. Zrobiliśmy błąd w jego projekcie i nie zwróciliśmy szczególnej uwagi na „void” jako typ zwracany i dlatego mamy langauge słowa kluczowe dla procedury. Jest to głównie prosta zmiana składni, ale jest to jedna z rzeczy, do których nie możesz się dostać, gdy otrzymasz duży kod działający w języku.
Trzy przypadki użycia dla void:
Sygnatury funkcji. void foo(int bar)
nie zwraca wartości. int bar(void)
nie podejmuje żadnych parametrów, ale jest to zwykle wyrażone listy pusty argument: int bar()
. Użycie w tym miejscu słowa kluczowego void odpowiada jego znaczeniu w języku angielskim.
Ogólny wskaźnik najwyższego typu, void *
który wskazuje na nieokreślone dane i nie można go wyłuskać. Tutaj znaczenie pustki różni się od innych znaczeń pustki: typ uniwersalny vs. brak typu.
W rzutach, (void) new Foo(this)
które oznaczają, że wartość zwracana jest celowo odrzucana. Tutaj użycie słowa kluczowego również odpowiada jego znaczeniu w języku angielskim.
Przypadki 1 i 2 zostały już omówione przez @Gerald, ale sprawa 3 nie została jeszcze rozwiązana.
Jeśli wyjaśniasz koncepcję początkującemu, pomocne może być użycie analogii. Użycie słowa „void” we wszystkich tych przypadkach jest analogiczne w znaczeniu do strony w książce, na której znajdują się słowa „Ta strona została celowo pozostawiona pusta”. Ma to na celu rozróżnienie kompilatora między czymś, co powinno być oznaczone jako błąd, a typem, który celowo ma pozostać pusty, ponieważ jest to zachowanie, którego chcesz.
Zawsze pojawia się w kodzie tam, gdzie normalnie można się spodziewać pojawienia się typu, takiego jak typ zwracany lub typ wskaźnika. Dlatego w C # void mapuje do rzeczywistego typu CLR, System.Void, ponieważ jest typem samym w sobie.
Niektóre języki programowania nigdy nie rozwinęły pojęcia pustki, podobnie jak niektóre kultury ludzkie nigdy nie wymyśliły pojęcia liczby zero. Void reprezentuje ten sam postęp w języku programowania, jaki pojęcie zera reprezentuje dla ludzkiego języka.
To znaczy „brak wartości”. Używasz void, aby wskazać, że funkcja nie zwraca wartości lub że nie ma parametrów lub obu. Jest to bardzo zgodne z typowymi zastosowaniami słowa void w języku angielskim.
Nie należy mylić wartości Void z wartością null. Null oznacza dla zmiennej, której adres znajduje się na stosie, wartość na stercie dla tego adresu jest pusta.
Void jest używany tylko w sygnaturach metod. W przypadku typów zwracanych oznacza to, że metoda nie zwróci niczego do kodu wywołującego. W przypadku parametrów oznacza to, że żadne parametry nie są przekazywane do metody
na przykład
void MethodThatReturnsAndTakesVoid(void)
{
// Method body
}
W C # możemy pominąć void dla parametrów i zapisać powyższy kod jako:
void MethodThatReturnsAndTakesVoid()
{
// Method body
}
Nie należy mylić wartości Void z wartością null. Null oznacza dla zmiennej, której adres znajduje się na stosie, wartość na stercie dla tego adresu jest pusta.
void oznacza, że nie będziesz zwracać żadnej wartości z funkcji lub metody
Void oznacza, że wartość zwracana przez funkcję nie jest wymagana we wszystkich trzech językach.