W jaki sposób komputer określa typ danych bajtu?

31

Na przykład, jeśli komputer 10111100zapisał jeden konkretny bajt pamięci RAM, w jaki sposób komputer może interpretować ten bajt jako liczbę całkowitą, znak ASCII lub coś innego? Czy dane typu są przechowywane w sąsiednim bajcie? (Nie sądzę, aby tak się stało, ponieważ spowodowałoby to użycie podwójnej ilości miejsca na jeden bajt.)

Podejrzewam, że być może komputer nawet nie zna rodzaju danych, które zna tylko program, który go używa. Domyślam się, że ponieważ RAM jest R AM i dlatego nie jest odczytywany sekwencyjnie, konkretny program po prostu mówi CPU, aby pobrać informacje z określonego adresu, a program określa, jak je traktować. Wydaje się, że pasuje to do programowania rzeczy, takich jak potrzeba rzutowania czcionek.

Czy jestem na dobrej drodze?

Bassinator
źródło
4
Na marginesie: jeśli mówisz o typach, musisz to robić w kontekście językowym. Kompilator musi zająć się takimi rzeczami (symbole, typy kontroli, operacje, rzutowanie, ram adresowy itp.). Procesor i pamięć RAM znają tylko bajty
jean
4
Typ danych bajtu jest bajtem. Poza tym komputer nic nie wie. Program może interpretować bajt lub grupę bajtów jako szczególny typ danych i próbować wykonywać na nich operacje, ale nie ma żadnych ograniczeń. Ta sama grupa bajtów może być interpretowana jako więcej niż jeden typ danych (tj. Rzutowanie wskaźników na typy wartości, związki typu C itp.). To, że pamięć RAM nie jest odczytywana sekwencyjnie, nie jest tak naprawdę istotne. - To więcej, ponieważ pamięć RAM jest uniwersalna. - Na przykład rejestry nie są odczytywane sekwencyjnie, ale są wpisywane.
BrainSlugs83
5
Bezwstydna wtyczka dla mnie, ale to pytanie zostało w zasadzie zadane programistom SE około miesiąc temu. Oto moja odpowiedź na to . W tym momencie jest trochę długa, ale atakuje ją z kilku różnych punktów widzenia.
Shaz
2
Jedną przydatną konsekwencją faktu, że sprzęt jest niezależny od typu danych, jest to, że pojedynczy bajt (lub słowo itp.) Może być interpretowany na wiele sposobów przez program. Warto zauważyć, że do obliczenia szybkiego odwrotnego pierwiastka kwadratowego używana jest tymczasowa interpretacja liczby zmiennoprzecinkowej jako liczby całkowitej .
Aoeuid
@ BrainSlugs83, czy możesz rozważyć przekształcenie tego w odpowiedź?
DW

Odpowiedzi:

38

Twoje podejrzenie jest słuszne. Procesor nie dba o semantykę danych. Czasami jednak robi to różnicę. Na przykład niektóre operacje arytmetyczne dają różne wyniki, gdy argumenty są semantycznie podpisane lub niepodpisane. W takim przypadku musisz powiedzieć procesorowi, którą interpretację zamierzałeś.

Programiści muszą ustalić, jakie są jej dane. Procesor wykonuje tylko rozkazy, błogo nieświadomy ich znaczenia lub celów.

Yuval Filmus
źródło
1
Jeśli chodzi o „kiedy argumenty są semantycznie podpisane lub niepodpisane”, skąd procesor wiedziałby? Operacje CPU po prostu widzą bajty parametrów i brakuje tego rodzaju świadomości kontekstu typu danych. Podajesz typ danych, wybierając odpowiednią operację procesora (lub robi to Twój kompilator).
Shiv
4
@Shiv W takich przypadkach procesor faktycznie otrzymuje inną instrukcję przetwarzania liczb podpisanych niż liczb niepodpisanych. Podobnie jak w podejrzeniach OP, program jest zobowiązany do podania tych szczegółów, ponieważ procesor nie jest świadomy.
Cort Ammon - Przywróć Monikę
2
Pracuję z komputerami, odkąd pamiętam, i chociaż wiem, że procesor nie dba o konstrukcje wysokiego poziomu, których używamy w programowaniu na wysokim poziomie, ale ten rozdział pojęć wciąż mnie przeraża
Loupax
1
@Loupax Cóż, praca z zestawem naprawdę niskiego poziomu bardzo pomaga - nawet mov al, 42jest rodzajem wysokiego poziomu - oczywiste jest, że istnieje tylko jedna możliwa instrukcja, którą można wywołać, ale wciąż jest nieco abstrakcyjna. Jednak użycie mov.8 al, 42jawnie czyni to boleśnie oczywistym :)
Luaan,
1
@Shiv: Chciałbym zauważyć, że istnieją maszyny, w których dane są zapisywane w pamięci. Są to tak zwane architektury znaczników pamięci (lub po prostu architektury znaczników), ale nie odniosły takiego sukcesu komercyjnego jak zwykłe architektury, częściowo dlatego, że teraz programujemy głównie w językach skompilowanych zamiast w asemblerze, a kompilator zajmuje się pisaniem. Zobacz: en.wikipedia.org/wiki/Tagged_architecture
slebetman
14

Jak już inni odpowiedzieli, dzisiejsze popularne procesory nie wiedzą, co zawiera dana pozycja pamięci; oprogramowanie decyduje.

Istnieją jednak inne możliwości. Maszyny Lisp na przykład zastosowały oznakowaną architekturę, która przechowywała typ każdej pozycji pamięci; w ten sposób sam sprzęt może wykonywać niektóre zadania w językach wysokiego poziomu.

I nawet teraz myślę, że możesz rozważyć bit NX w architekturze Intel, AMD, ARM i innych, aby zastosować tę samą zasadę: rozróżnij na poziomie sprzętowym, czy dana strefa pamięci zawiera dane lub instrukcje.

Ponadto, dla kompletności, w architekturach Harvarda (jak niektóre mikrokontrolery) dane i instrukcje są fizycznie oddzielone, więc CPU ma pewne pojęcie o tym, co czyta.

W tym pytaniu Quora znajduje się komentarz na temat działania oznaczonej pamięci, jej wpływu na wydajność i upadku, i wiele więcej.

Hmijail
źródło
Architektura oznaczona tagami jest interesującą notatką. Czy byłoby znacznie szybciej?
Bassinator
4

Tak. Program pobiera bajt z pamięci i może interpretować go w dowolny sposób.

David Richerby
źródło
3

Brak adnotacji typu.
Pamięć RAM przechowuje czyste dane, a następnie program określa, co robić.

Z rejestrami procesora jest nieco trudniej, jeśli masz rejestry danego typu (np. FPU), mówisz, co jest w środku.
Operacje na rejestrach zmiennoprzecinkowych jawnie wykorzystują dane wpisane. Ty lub twój kompilator powiecie, co i kiedy należy tam umieścić, abyście nie mieli takiej swobody.
Komputer nie przyjmuje żadnych założeń dotyczących bazowych danych w pamięci RAM, aw rejestrach z jednym wyjątkiem - rejestry typowane w CPU są znanego typu, zoptymalizowane pod kątem radzenia sobie z tym. Ma to tylko pokazać, że istnieją miejsca, w których dane mają być typu oczekiwanego, ale nic nie stoi na przeszkodzie, aby rzutować ciągi na zmiennoprzecinkowe i pomnożyć je.

W językach programowania określasz typ, a w językach wyższego poziomu dane są ogólne, a kompilator / interpreter / VM koduje to, co jest w środku z narzutem.
Na przykład w C Twój typ wskaźnika mówi, co zrobić z danymi i jak uzyskać do nich dostęp.

Oczywiście możesz odczytać ciąg znaków (znaków) i traktować je jako wartości zmiennoprzecinkowe, liczby całkowite i mieszać je.

Zło
źródło
Nawet bity w rejestrze FPU nie zawsze reprezentują wartości zmiennoprzecinkowe. W dawnych czasach (może już nie tyle?) Powszechną optymalizacją było używanie rejestrów zmiennoprzecinkowych (64-bitowych lub większych) do kopiowania danych szybciej niż rejestry ogólnego przeznaczenia / liczby całkowite (32-bitowe), które są dwa razy większe, na ogół byli w stanie skopiować dane dwa razy szybciej.
Seth
1
Całkowicie się z tobą zgadzam, dlatego napisałem, że ktoś może tam naciskać. W tym samym czasie ludzie wykonywali operacje zmiennoprzecinkowe na liczbach całkowitych, ponieważ było to szybsze. O to chodzi!
Zło
@HCBPshenanigans istnieją instrukcje, które manipulują wartościami zmiennoprzecinkowymi. Jeśli stosuje się FADD, ma sens tylko to, że grupy pamięci (4,8 lub 10) przechowują liczby zmiennoprzecinkowe. Dotyczy to kilku rodzajów instrukcji: pomnożenie dwóch liczb całkowitych ma sens tylko wtedy, gdy są liczbami całkowitymi, przeskok ma sens tylko wtedy, gdy jest to adres.
JDługosz
@seth i evilJS, którego nie zakłada się w przypadku starszych 8087 instrukcji zmiennoprzecinkowych, ale dotyczy to nowszych rejestrów CIMD, które mogą być używane tylko do ładowania / zapisywania bez interpretacji (choć muszą być wyrównane) oraz zastrzeżenie że jeśli rejestry CIMD nigdy nie były używane, nie trzeba ich zapisywać w przełączniku kontekstu. Jeśli przenosisz (tylko) 8 bajtów za pośrednictwem rejestru XMM, jest to strata netto, ponieważ cały zestaw musi zostać zapisany.
JDługosz
3

CPU nie dba o to, wykonuje kod asemblera, który po prostu przenosi dane, przesuwa je, dodaje lub pomnaża ...

Typy danych to koncepcja języka wyższego poziomu: w C lub C ++ musisz określić Typy dla każdego manipulowanego elementu danych; kompilator C / C ++ dba o przekształcenie tych danych w odpowiednie polecenia do przetworzenia przez CPU (kompilatory zapisują kod asemblera)

W niektórych językach nawet wyższego poziomu można wywnioskować typy: na przykład w Pythonie lub JavaScript nie trzeba określać typów danych, ale dane mają typ i nie można dodać ciągu z liczbą całkowitą, ale można dodać liczba zmiennoprzecinkowa z liczbą całkowitą: „kompilator” (który w przypadku Javascript jest kompilatorem JIT (Just in Time). Javascript jest często nazywany językiem „interpretowanym”, ponieważ w przeszłości przeglądarki interpretują kod JavaScript, ale obecnie silniki JavaScript są kompilatorami.

Kod, zawsze kończy się kompilacja do kodu maszynowego, ale oczywiście format kodu maszynowego zależy od komputera, na który celujesz (64-bitowy kod x86 nie będzie działał na maszynie 32-bitowej x86 lub procesorze ARM)

Tak więc w uruchomionym interpretowanym kodzie jest zaangażowanych wiele warstw.

Java i C # są innymi interesującymi, ponieważ kod Java lub C # jest technicznie „kompilowany” do pliku binarnego Java (kod bajtowy), ale sam ten kod jest następnie interpretowany przez środowisko wykonawcze Java, które jest specyficzne dla sprzętu bazowego (należy zainstalować środowisko JRE ukierunkowane na odpowiednią maszynę do uruchamiania plików binarnych Java (Jars))

MrE
źródło
Kompilator kompiluje, czy to JIT, czy nie; a tłumacz interpretuje bez kompilacji (bo jeśli nie, byłby to kompilator!). To są bardzo różne rzeczy. A jeśli chodzi o „zabawną Javę” z powodu interpretacji kodu bajtowego, weź pod uwagę, że nawet kod maszynowy x86 zostanie zinterpretowany (a nawet skompilowany?) Przez sam mikroprocesor w mikrokod .
hmijail
Dzięki za wyjaśnienie ... Uzgodnione: kompilator kompiluje, a tłumacz interpretuje. W przypadku Javascript historia jest nieco skomplikowana, ponieważ niektóre starsze przeglądarki interpretują kod, podczas gdy bardziej nowoczesne przeglądarki kompilują właśnie na czas, prawdopodobnie dlatego wciąż jest nazywany językiem „interpretowanym”, mimo że technicznie nie jest już.
Mr
Ale AFAIK, JS zaczyna interpretować, a następnie może zostać skompilowany w razie potrzeby. A JITy mogą przełączyć się z interpretowanego na skompilowany na ponownie zinterpretowany, w zależności od wielu rzeczy. Na przykład fragment kodu może zostać skompilowany dla zmiennej mającej dany typ; ale potem kod jest uruchamiany ponownie z tą zmienną o innym typie, więc istniejącego skompilowanego kodu nie można użyć, więc interpreter wskakuje - dopóki kod nie zostanie ponownie skompilowany dla nowego typu ...
hmijail
Przytaczasz mnie do czegoś, czego nie powiedziałem, usuń to, ponieważ jest całkowicie błędne. Mikrokod NIE ma nic wspólnego z systemem operacyjnym; to coś wewnętrznego w mikroprocesorze. Wersja 32- lub 64-bitowa również nie ma z tym nic wspólnego.
hmijail
3

Typy danych nie są funkcją sprzętową. Procesor zna kilka (cóż, dużo) różnych poleceń. Są to tak zwane zestaw instrukcji procesora.

Jednym z najbardziej znanych jest zestaw instrukcji x86 . Jeśli szukasz „pomnóż” na tej stronie, otrzymasz 50 wyników. MULPDi MULSDdo mnożenia FIMULliczb podwójnych, do mnożenia liczb całkowitych ...

Te polecenia działają na rejestrach. Rejestry to gniazda pamięci, które mogą zawierać stałą liczbę bitów (często 32 lub 64, w zależności od architektury używanej przez procesor), bez względu na to, co te bity reprezentują. Stąd instrukcja CPU interpretuje wartości rejestrów w inny sposób, ale same wartości nie mają typów.

Przykład podany na PyCon 2017 przez Stuarta Williamsa :

wprowadź opis zdjęcia tutaj

Martin Thoma
źródło
1
Zauważ, że nie jest to do końca prawdą: istnieją rejestry specjalnego przeznaczenia, które nie mogą zawierać dowolnych wartości (na przykład rejestry wskaźników, które nie są tylko adresami i nie pozwalają na dowolne dodawanie, lub rejestry zmiennoprzecinkowe, w których można przechowują wartości nienormalizowane). Ale twoja odpowiedź jest poprawna dla rejestrów ogólnego przeznaczenia w większości architektur.
Gilles „SO- przestań być zły”
2

... że określony program po prostu mówi CPU, aby pobrać informacje z określonego adresu, a program określa, jak je traktować.

Dokładnie. Ale pamięć RAM nie jest odczytywana „sekwencyjnie” i oznacza pamięć o dostępie bezpośrednim, co jest dokładnie odwrotne.

Poza tym wiedząc, co bajt jest , nie wiem nawet, czy jest to bajt lub fragment większej pozycji jak liczbę zmiennoprzecinkową.

Chciałbym dodać do innych odpowiedzi, podając kilka konkretnych przykładów.

Zastanów się 01000001. Program może kopiować je z jednego miejsca do drugiego jako część dużej paczki danych bez względu na jego znaczenie. Ale skopiowanie go na adres używany przez bufor wideo w trybie tekstowym spowoduje, że litera Abędzie wyświetlana w pewnej pozycji na ekranie. Dokładnie taka sama akcja, gdy karta jest w trybie graficznym CGA, wyświetli czerwony i niebieski piksel.

W rejestrze może to być liczba 65 jako liczba całkowita. Wykonywanie arytmetyki w celu ustawienia bitu 32 może oznaczać wszystko bez kontekstu, ale może w szczególności polegać na zmianie litery na małe litery.

Procesor 8086 (nadal) ma specjalne instrukcje o nazwie DAA ※, które są używane, gdy rejestr zawiera 2 cyfry dziesiętne, więc jeśli właśnie użyłeś tej instrukcji, interpretujesz ją jako dwie cyfry 41.

Programy ulegają awarii, ponieważ słowo pamięci jest odczytywane, myśląc, że jest wskaźnikiem, gdy zapisano tam coś innego.

Za pomocą debugera, sprawdzającego pamięć, mapa służy do kierowania interpretacją wyświetlacza. Bez tej informacji o symbolu debuger niskiego poziomu pozwala określić: pokaż ten adres jako 16-bitowe słowa, pokaż ten adres jako długi zmiennoprzecinkowy, jako ciągi znaków ... cokolwiek. Zastanawianie się nad zrzutem pakietu sieciowego lub nieznanym formatem pliku stanowi wyzwanie.

Jest to główne źródło mocy i elastyczności we współczesnej architekturze komputerowej: komórka pamięci może oznaczać cokolwiek , dane lub instrukcje, domyślnie tylko w tym, co „znaczy” dla programu przez to, co robi z wartością i jak wpływa na kolejne operacje. znaczenie jest głębsze niż szerokość całkowita: czy te znaki ... znaki w ascii lub ebcdic? Tworzysz słowa w języku angielskim lub w kodach produktów SQU? Adres do wysłania lub adres zwrotny, z którego pochodzi? Interpretacja najniższy poziom (bity logiczne; całkowitą podobny, podpisane lub niepodpisane; pływak; BCD; pointer) jest kontekstowa na poziomie instrukcji ustawiony, ale widać, że to wszystko kontekst w pewnym poziom: doadres jest taki, jaki jest, ponieważ znajduje się na kopercie. Jest kontekstowy z zasadami listonosza, a nie CPU. Kontekst jest jednym wielkim kontinuum, z bitami na jednym końcu.


※ Przypis: Instrukcja DAA jest zakodowana jako bajt 00100111. Tak więc ten bajt jest wspomnianą wcześniej instrukcją, jeśli jest czytany w strumieniu instrukcji, a cyfry, 27jeśli są interpretowane jako cyfry bcd, a 0x27 = 39 jako liczba całkowita, która jest liczbą 9 w ASCII, i częścią tablicy przerwań (połowa INT 13 2-bajtowy adres, używany w procedurach serwisowych BIOS).

JDługosz
źródło
1

Jedynym sposobem, w jaki komputer wie, że miejscem w pamięci jest instrukcja, jest to, że rejestr specjalnego przeznaczenia zwany wskaźnikiem instrukcji wskazuje na nią w tym lub innym miejscu. Jeśli wskaźnik instrukcji wskazuje na słowo pamięci, jest ono ładowane jako instrukcja. Poza tym komputer nie ma możliwości poznania różnicy między programami a innymi typami danych.

Dummy Dum
źródło