Jaka jest różnica między zmiennymi a wskaźnikami?


10

Podczas lektury artykułu opisującego różnice w OO i programowaniu funkcjonalnym natknąłem się na wskaźniki funkcji. Minęło trochę czasu, odkąd ukończyłem studia informatyczne (2003), więc szukałem wskazówek, aby odświeżyć moją pamięć.

Wskaźniki to zmienne, które zawierają odniesienie do adresu pamięci. Można je uznać za wskazujące na dane zawarte w tym adresie pamięci, jeśli takie dane istnieją. Lub, tak jak w przypadku tego artykułu, mogą wskazywać punkt wejścia do sekcji kodu i mogą być użyte do wywołania tego kodu.

Dlaczego różni się to od zmiennej? Zmienne są symbolicznymi nazwami adresów pamięci, a kompilatory zastąpią nazwę faktycznym adresem. Oznacza to, że zmienne zawierają odniesienia do lokalizacji pamięci i można uznać, że wskazują dane pod tym adresem, jeśli takie dane istnieją.

Jeśli różnica polega na zachowaniu (być może wskaźnik nie może zostać ponownie przypisany w czasie wykonywania, lub można mu przypisać tylko nazwę zmiennej symbolicznej, a nie inną wartość), czy to nie znaczy, że jest to tylko zmienna określonego typu, typ wskaźnika? W ten sam sposób zmienna zadeklarowana jako liczba całkowita jest ograniczona przez kompilację, do czego może być używana.

Czego tu brakuje?


4
Nic, wskaźnik nie jest w rzeczywistości typem, którego interpretacja semantyczna jest taka, że ​​zawartość zmiennej jest adresem. Zauważ oczywiście, że istnieją dwa adresy, jest adres wskaźnika (tzn. Gdzie zmienna jest przechowywana) i adres, do którego odwołuje się wskaźnik (rzeczywiste dane pod adresem zmiennej). Wskaźnik jest rodzajem odniesienia .
Luke Mathieson

Odpowiedzi:


8

Twoje pytanie jest interesujące na kilka sposobów, ponieważ wymaga starannego rozróżnienia dla kilku zagadnień. Ale twoja wizja wydaje mi się zasadniczo poprawna. Nie przeczytałem twojego odniesienia przed napisaniem większości tej odpowiedzi, aby uniknąć popychania mojej odpowiedzi.

Po pierwsze, twoje oświadczenie Variables are symbolic names for memory addressesjest prawie poprawne, ale myli koncepcję i jej zwykłą implementację. Zmienna jest tak naprawdę tylko kontenerem, który może zawierać wartość, którą można zmienić. Zazwyczaj ten kontener jest implementowany na komputerze jako blok pamięci, charakteryzowany przez adres i rozmiar, ponieważ zmienne mogą zawierać obiekt, który wymaga reprezentacji z większą lub mniejszą ilością informacji.

Ale rozważę głównie bardziej abstrakcyjny punkt widzenia semantyki języków, niezależnie od technik implementacyjnych.

Zatem zmienne są tylko kontenerami z abstrakcyjnego punktu widzenia. Taki pojemnik nie musi mieć nazwy. Jednak języki często mają zmienne, które są nazywane przez powiązanie z nim identyfikatora, więc użycie zmiennej może być wyrażone przez identyfikator. Zmienna może faktycznie mieć kilka identyfikatorów za pośrednictwem różnych mechanizmów aliasingu. Zmienna może być również częścią większej zmiennej: przykładem jest komórka zmiennej tablicowej, którą można nazwać określając zmienną tablicową i indeks komórki, ale równie dobrze można ją powiązać z identyfikatorami poprzez aliasing.

Celowo używam słowa „ kontener”, który jest nieco neutralny, aby uniknąć przywoływania innych słów, które mogą być technicznie ładowane semantycznie. W rzeczywistości jest on zbliżony do koncepcji odniesienia opisanej w wilipedia , która często jest mylona z adresem pamięci. Sam wskaźnik słowa jest często rozumiany jako adres pamięci, ale nie sądzę, aby miał on znaczenie przy rozważaniu większości języków wysokiego poziomu i prawdopodobnie nieodpowiedni w dokumencie do dyskusji, do którego się odwołujesz (chociaż adresów można używać), ponieważ jest niewłaściwy odnoszące się do konkretnego wdrożenia. Jest jednak odpowiedni dla języka takiego jak C, który ma być znacznie bliższy koncepcjom implementacji i architekturze maszyny.

W rzeczywistości, jeśli spojrzysz na zmienne lub wartości na poziomie implementacji, może istnieć kilka złożonych systemów pośrednich, „wskaźników na poziomie maszyny”, ale które są (i powinny być) niewidoczne dla użytkownika, tak że abstrakcyjny punkt widzenia Rozwijam się, może być ważny. W przypadku większości języków programowania użytkownik nie powinien się martwić, a nawet wiedzieć o implementacji, ponieważ implementacja może się znacznie różnić w zależności od języka. Może to nie być prawdą w przypadku niektórych języków, takich jak C, które są celowo zbliżone do architektury maszyny, jako zaawansowany zamiennik języków asemblerowych, które są prawie bezpośrednio związane z jawnym kodowaniem binarnym, ale zdecydowanie za niski poziom, aby można było z nich wygodnie korzystać w większości sytuacje.

To, co użytkownik języka powinien wiedzieć, a czasem powinien być jeszcze mniejszy, to jakie są wartości i powiązane operacje, gdzie można je zawrzeć, jak można je powiązać z nazwami, jak działa system nazewnictwa, jak nowe rodzaje wartości do zdefiniowania itp.

Kolejną ważną koncepcją są identyfikatory i nazewnictwo. Nazwanie bytu (wartości) można wykonać przez powiązanie identyfikatora z wartością (zwykle w deklaracji). Ale wartość można również uzyskać przez zastosowanie operacji do innych nazwanych wartości. Nazwy można ponownie wykorzystać, a istnieją reguły (reguły określania zakresu) w celu ustalenia, co jest powiązane z danym identyfikatorem, zgodnie z kontekstem użycia. Istnieją również specjalne nazwy, zwane literałami, w celu nazwania wartości niektórych domen, takich jak liczby całkowite (np612) lub boolean (np. true ).

Powiązanie niezmienionej wartości z identyfikatorem jest zwykle nazywane stałą. Litterals są stałymi w tym sensie.

„Pojemniki wartości” można również traktować jako wartości, a ich powiązanie z identyfikatorem jest zmienną w zwykłym „naiwnym” znaczeniu, którego używasz. Można więc powiedzieć, że zmienna jest „stałą kontenerową”.

Teraz możesz się zastanawiać, jaka jest różnica między powiązaniem identyfikatora z wartością (stała deklaracja) lub przypisaniem wartości do zmiennej, tj. Zapisaniem wartości w kontenerze zdefiniowanym jako stała kontenera. Zasadniczo deklaracja może być postrzegana jako operacja definiująca notację, która wiąże identyfikator, który jest bytem syntaktycznym, z pewną wartością, która jest bytem semantycznym. Przypisanie jest operacją czysto semantyczną, która modyfikuje stan, tj. Modyfikuje wartość kontenera. W pewnym sensie deklaracja jest meta pojęciem bez efektu semantycznego, innym niż dostarczenie mechanizmu nazewnictwa (tj. Składniowego) dla jednostek semantyki.

W rzeczywistości przypisania są operacjami semantycznymi, które pojawiają się dynamicznie podczas wykonywania programu, podczas gdy deklaracje mają bardziej składniowy charakter i zwykle należy je interpretować w tekście programu, niezależnie od wykonania. Właśnie dlatego ustalanie zakresu (tj. Określanie zakresu tekstu) jest zwykle naturalnym sposobem zrozumienia znaczenia identyfikatorów.

Po tym wszystkim mogę powiedzieć, że wartość wskaźnika to po prostu inna nazwa kontenera, a zmienna wskaźnika to zmienna kontenera, tzn. Kontener (stały), który może zawierać inny kontener (z możliwymi ograniczeniami narzuconej gry narzuconymi przez niektórych system typów).

Jeśli chodzi o kod, stwierdzasz [pointers] might indicate the entry point to a section of code and can be used to call that code. W rzeczywistości nie jest to do końca prawda. Część kodu jest często sama w sobie bez znaczenia (z wysokiego poziomu lub z punktu widzenia implementacji). Z punktu widzenia wysokiego poziomu kod zwykle zawiera identyfikatory i należy je interpretować w kontekście statycznym, w którym zostały zadeklarowane. Ale w rzeczywistości możliwe jest powielanie tego samego kontekstu statycznego, głównie z powodu rekurencji, która jest zjawiskiem dynamicznym (w czasie wykonywania), a kod można wykonać tylko w odpowiedniej dynamicznej instancji kontekstu statycznego. Jest to nieco skomplikowane, ale konsekwencją jest to, że właściwą koncepcją jest zamknięcie, które kojarzy kawałek kodu i środowisko, w którym identyfikatory mają być interpretowane. Zamknięcie jest właściwą koncepcją semantyczną, tj. Jest właściwie definiowaną wartością semantyczną. Następnie możesz mieć stałe zamknięcia, zmienne zamknięcia,

Funkcja jest zamknięciem, zwykle z pewnymi parametrami do zdefiniowania lub zainicjowania niektórych jej bytów (stałych i zmiennych).

Pomijam wiele wariantów wykorzystania tych mechanizmów.

Zamknięcia mogą służyć do definiowania struktur OO w imperatywnych lub funkcjonalnych językach. Właściwie wczesne prace nad stylem OO (prawdopodobnie przed nazwą) zostały wykonane w ten sposób.

Artykuł, do którego się odwołujesz, który szybko przejrzałem, wydaje się interesujący, napisany przez kompetentną osobę, ale być może nie jest łatwy do przeczytania, jeśli nie masz znaczącego doświadczenia z różnymi językami i leżącymi u ich podstaw modelami obliczeniowymi.

Pamiętaj jednak: wiele rzeczy znajduje się w oczach patrzącego, o ile zachowuje spójny pogląd. Punkty widzenia mogą się różnić.

Czy to odpowiada na twoje pytanie?

PS: To długa odpowiedź. Jeśli uważasz, że jakaś jej część jest nieodpowiednia, proszę wyraźnie powiedzieć, która to jest. Dziękuję Ci.


Musiałem ją przeczytać kilka razy, ale myślę, że to odpowiada na moje pytanie, tak. Chociaż moje definicje są zbyt realizacja centric, pomysł, że wskaźnik jest szczególnym rodzajem zmiennej wydaje się być dokładna, czyli „wartość wskaźnika jest po prostu inna nazwa dla pojemnika, a zmienny wskaźnik jest zmienną pojemnik” , gdzie nie rozróżniasz między wskaźnikiem zawierającym adres bloku kodu a pojemnikiem zawierającym pojemnik zawierający zamknięcie. Czy istnieje różnica między kontekstem statycznym a programem w trakcie wykonywania?
NectarSoft,

1
@NectarSoft Rozróżnienie dotyczy tylko bloku kodu i zamknięcia. Mówię o tym, że blok kodu sam w sobie, odizolowany od jakiegokolwiek kontekstu, zwykle nic nie znaczy. Jeśli powiem wam, że „ jeśli math raths są większe niż borogove, to gołębie wychodzą ”, zdanie to nic nie znaczy, ponieważ brakuje ci kontekstu, w którym zdefiniowane są wszystkie te pojęcia. Ten statyczny kontekst to zwykle tekst otaczający fragment kodu. Problem polega na tym, że sam kontekst statyczny może mieć kilka instancji wykonawczych, a fragment kodu musi odnosić się tylko do jednej z nich.
babou

1
@NectarSoft (ciąg dalszy) Tak więc wartością zamknięcia jest powiązanie fragmentu kodu z dynamicznym wystąpieniem kontekstu statycznego, który nadaje znaczenie temu fragmentowi. Powiązanie tego samego fragmentu kodu z inną dynamiczną instancją tego samego kontekstu statycznego daje inne zamknięcie. Zazwyczaj kod może wykorzystywać zmienną należącą do tego kontekstu, ale będzie to inna zmienna dla każdej dynamicznej instancji kontekstu, chociaż jego nazwa (zdefiniowana statycznie) pozostaje taka sama. Czy to wyjaśnia problem, czy powinienem zbudować przykład w odpowiedzi (format komentarzy jest ograniczony)?
babou

To wyjaśnia problem, dziękuję, jednocześnie poruszając inne pytania, o których poświęcę trochę czasu. Na przykład, jeśli wymagany jest odrębny wskaźnik dla każdego zamknięcia, wydaje się, że wskaźnik staje się częścią kontekstu dynamicznego i dlatego należy do zamknięcia! Zastanawiam się także nad granicami zamknięcia i hierarchią zamknięcia, ponieważ każdy z tych kontekstów powiązanych ze statycznym blokiem kodu i do którego odwołuje się wskaźnik, koniecznie będzie zmienną w swoim zamknięciu. Wszystko to jest jednak poza tematem, więc zrobię lekturę i może zadam kolejne pytanie, kiedy
utknę

@NectarSoft Właściwie. budując zamknięcie, starasz się ograniczyć kontekst związany z kodem do tego, co jest konieczne do nadania temu kodowi odpowiedniego znaczenia (do pewnych praktycznych ograniczeń, aby uniknąć informacji o mikro-zarządzaniu). Można to ustalić statycznie.
babou

2

Różnica polega na definicji i zastosowaniu, wskaźnik jest wyspecjalizowaną zmienną do przechowywania adresu pamięci innej zmiennej; w kategoriach OO prawdopodobnie można by uznać, że wskaźnik odziedziczył swoje zachowanie po ogólnej klasie zwanej zmienną.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.