Czy język programowania C był uważany za język niskiego poziomu, kiedy się pojawił?

151

Obecnie język C jest uważany za język niskiego poziomu , ale czy w latach 70. był uważany za język niski? Czy ten termin był nawet w użyciu?

Wiele popularnych języków wyższego poziomu istniało dopiero w połowie lat 80. i później, więc jestem ciekawy, czy i jak zmieniła się natura niskiego poziomu na przestrzeni lat.

joeyfb
źródło
13
Jako jeden punkt danych, około 1978 r., Niektórzy mentorzy programowania opisali mi C jako chwalebny język asemblera.
Ben Crowell
7
@BenCrowell Nie jestem pewien, co oznacza „gloryfikowany” w kontekście twojego oświadczenia, ale doświadczyłem nazywania C uniwersalnym (= niezależnym od platformy) językiem asemblera .
Melebius
13
Co ciekawe, należy postawić sprawę, że C nie jest językiem niskiego poziomu i jest teraz mniej niż w latach 70., ponieważ abstrakcyjna maszyna C jest dalej usuwana z nowoczesnego sprzętu niż z PDP-11.
Tom
5
Myśląc o tym, możesz również pomyśleć o pochodzeniu - Unix jest napisany w C, c działa na Unixie i kompiluje między innymi na innych platformach. Wszystko, co nie było konieczne do kompilacji Uniksa, było niepotrzebnym narzutem, a głównym celem C było uproszczenie pisania / przenoszenia kompilatora. W tym celu był to DOKŁADNY poziom, więc nie myślę o C jako o wysokim lub niskim poziomie, myślę o nim jako o narzędziu do przenoszenia Uniksa, który, podobnie jak prawie wszystkie narzędzia Uniksa, jest niezwykle przystosowalny do wielu problemów.
Bill K
4
Warto zauważyć, że seplenienie zostało wynalezione w 1958 r.
Prime

Odpowiedzi:

144

Aby odpowiedzieć na historyczne aspekty pytania:

Filozofia projektowania została wyjaśniona w języku programowania C napisanym przez Briana Kernighana i projektanta C Dennisa Ritchie, „K&R”, o którym być może słyszałeś. Przedmowa do pierwszego wydania mówi

C nie jest językiem „bardzo wysokiego poziomu” ani „dużym”…

i wprowadzenie mówi

C jest językiem stosunkowo „niskiego poziomu” ... C nie zapewnia żadnych operacji bezpośrednio związanych z obiektami złożonymi, takimi jak ciągi znaków, zestawy, listy lub tablice. Nie ma operacji, które manipulują całą tablicą lub ciągiem ...

Lista jest wyświetlana przez chwilę, zanim tekst będzie kontynuowany:

Chociaż brak niektórych z tych funkcji może wydawać się poważnym brakiem, ... utrzymanie języka na minimalnym poziomie ma realne zalety.

(Mam tylko drugie wydanie z 1988 r., Ale poniższy komentarz wskazuje, że cytowany tekst jest taki sam w pierwszym wydaniu z 1978 r.)

Tak więc, wtedy używane były terminy „wysoki poziom” i „niski poziom”, ale C zaprojektowano tak, aby mieściło się gdzieś w widmie pomiędzy nimi. Możliwe było pisanie kodu w C, który był przenośny na różnych platformach sprzętowych, i to było główne kryterium, czy język był wówczas uważany za wysoki poziom. C brakowało jednak niektórych cech charakterystycznych dla języków wysokiego poziomu i była to decyzja projektowa na korzyść prostoty.

gatkin
źródło
42
To doskonała odpowiedź! Weryfikowalne dowody historyczne + zeznanie aktora najlepiej poinformowanego o znaczeniu niskiego i wysokiego poziomu w okresie, o którym mowa w PO. Nawiasem mówiąc, potwierdzam, że cytaty były już w wydaniu z 1978 roku.
Christophe
157

Zależy to od twojej definicji języka wysokiego i niskiego poziomu. Gdy opracowano C, wszystko, co było na wyższym poziomie niż asembler, było uważane za język wysokiego poziomu. To niski pasek do wyczyszczenia. Później terminologia ta została przesunięta do tego stopnia, że ​​niektórzy uważają, że nawet Java jest językiem niskiego poziomu.

Nawet w wysokopoziomowym krajobrazie językowym lat 70. warto zauważyć, że poziom C jest dość niski. Język C to w zasadzie B plus prosty system typów, a B to niewiele więcej niż wygodna proceduralna / strukturalna warstwa składniowa do złożenia. Ponieważ system pisma jest dopasowywany retro w stosunku do nietypowego języka B, nadal można pominąć adnotacje typu w niektórych miejscach i intzostaną one przyjęte.

C świadomie pomija drogie lub trudne do wdrożenia funkcje, które były już dobrze ugruntowane w tym czasie, takie jak

  • automatyczne zarządzanie pamięcią
  • zagnieżdżone funkcje lub zamknięcia
  • podstawowe OOP lub coroutines
  • bardziej wyraziste systemy typów (np. typy o ograniczonym zasięgu, typy zdefiniowane przez użytkownika, takie jak typy rekordów, silne pisanie,…)

C ma kilka interesujących funkcji:

  • obsługa rekurencji (w wyniku zmiennych automatycznych opartych na stosie, w porównaniu do języków, w których wszystkie zmienne mają globalny czas życia)
  • wskaźniki funkcji
  • Zdefiniowane przez użytkownika typy danych (struktury i związki) zostały zaimplementowane wkrótce po pierwszej wersji C.
  • Reprezentacja ciągu C (wskaźnik do znaków) jest w rzeczywistości ogromnym ulepszeniem w stosunku do B, które kodowało wiele liter w jednym słowie maszynowym.
  • Pliki nagłówkowe C były hackem wydajnościowym, mającym na celu utrzymanie małych jednostek kompilacyjnych, ale także zapewniającym prosty system modułów.
  • Nieograniczone wskaźniki i arytmetyka wskaźników w stylu zespołu, w porównaniu do bezpieczniejszych odniesień. Wskaźniki są z natury niebezpieczną funkcją, ale są również bardzo przydatne w przypadku programowania na niskim poziomie.

W czasie, gdy C został opracowany, inne innowacyjne języki, takie jak COBOL, Lisp, ALGOL (w różnych dialektach), PL / I, SNOBOL, Simula i Pascal zostały już opublikowane i / lub były szeroko stosowane w określonych obszarach problemowych. Ale większość tych istniejących języków była przeznaczona do programowania na komputerach mainframe lub były akademickimi projektami badawczymi. Np. Kiedy ALGOL-60 został po raz pierwszy zaprojektowany jako uniwersalny język programowania, niezbędna technologia i informatyka do jego wdrożenia jeszcze nie istniały. Niektóre z nich (niektóre dialekty ALGOL, PL / I, Pascal) były również przeznaczone do programowania na niskim poziomie, ale zwykle miały bardziej złożone kompilatory lub były zbyt bezpieczne (np. Brak nieograniczonych wskaźników). Pascal wyraźnie nie ma dobrego wsparcia dla tablic o zmiennej długości.

W porównaniu z tymi językami, C odrzuca „eleganckie” i drogie funkcje, aby być bardziej praktycznym w programowaniu na niskim poziomie. C nigdy nie był przede wszystkim projektem badawczym dotyczącym projektowania języka. Zamiast tego był pochodną rozwoju jądra Unixa na minikomputerze PDP-11, który był stosunkowo ograniczony pod względem zasobów. Ze względu na swoją niszę (minimalistyczny język niskiego poziomu do pisania Uniksa z kompilatorem jednoprzebiegowym, który jest łatwy do przeniesienia) C jest absolutnie doskonały - a ponad 45 lat później nadal jest lingua franca programowania systemów.

amon
źródło
17
Mały dodatek dla osób, które nie są świadome tego, co było konieczne dla istniejącej rodziny ALGOL i języków Pascal: Te języki miały zagnieżdżone leksykalnie funkcje, w których można było uzyskać dostęp do (lokalnej) zmiennej zadeklarowanej w funkcjach zewnętrznych. Oznaczało to, że albo musiałeś utrzymywać „wyświetlacz” - tablicę wskaźników do zewnętrznych zakresów leksykalnych - przy każdym wywołaniu funkcji i powrocie (to zmieniło poziom leksykalny) - albo musiałeś połączyć łańcuchy zakresów leksykalnych w górę stosu i każdego takiego dostępu do zmiennej wymagało wielu pośrednich przeskoków w górę stosu, aby go znaleźć. Kosztowny! C porzucił to wszystko. Wciąż za tym tęsknię.
davidbak
12
@davidbak: Interfejs ABI systemu V86 x86-64 (inaczej konwencja wywoływania w systemie Linux / OS X) definiuje się %r10jako „statyczny wskaźnik łańcucha”, o którym dokładnie mówisz. W przypadku C jest to po prostu kolejny rejestr zadrapania z zapisem połączeń, ale myślę, że Pascal by go użył. (Funkcje zagnieżdżone w GNU C używają go do przekazywania wskaźnika do zakresu zewnętrznego, gdy taka funkcja nie jest wbudowana (np. Jeśli utworzysz wskaźnik funkcji, aby kompilator utworzył na stosie trampolinę kodu maszynowego): Dopuszczalność regularnych użycie r10 i r11 )
Peter Cordes
2
@PeterCordes Fascynujące! Pascal był nadal szeroko stosowany, kiedy pojawił się System V (choć nie wiem, kiedy formalna SysV ABI została zdefiniowana). Twoja linkowana odpowiedź jest bardzo pouczająca.
davidbak
3
C ma typy zdefiniowane przez użytkownika (struct / union). Podejrzewam, że pozostałe „funkcje” zostały pominięte, ponieważ mają zerowe lub negatywne zastosowanie (chyba że bierzesz udział w konkursie zaciemnionego kodu :-)), ponieważ szkodzą celowi, jakim jest utrzymanie prostego i wyrazistego języka .
jamesqf
6
@jamesqf: ale bardzo wcześnie C nie miał struktury przypisania; Wydaje mi się, że musisz samodzielnie zapisywać lub kopiować członków zamiast pisać, a = b;aby skopiować całą strukturę tak, jak to możliwe w ISO C89. Tak więc we wczesnym C typy zdefiniowane przez użytkownika były zdecydowanie drugiej kategorii i mogły być przekazywane tylko przez referencję jako argumenty funkcji. Niechęć C do tablic, a także Dlaczego C ++ obsługuje przypisanie tablic do struktur wewnątrz struktur, ale ogólnie nie?
Peter Cordes
37

Na początku lat 70. C był oszałamiającym powiewem świeżego powietrza przy użyciu nowoczesnych konstrukcji tak skutecznie, że cały system UNIX można było przepisać z języka asemblera na C przy znikomej ilości miejsca lub wydajności. W tym czasie wielu współczesnych nazywało to językiem wysokiego poziomu.

Autorzy C, przede wszystkim Dennis Ritchie, byli bardziej ostrożni, aw artykule czasopisma Bell System Technical Journal powiedział: „C nie jest językiem wysokiego poziomu”. Z wykrzywionym uśmiechem i zamierzając być prowokujący, Dennis Ritchie powiedziałby, że to język niskiego poziomu. Głównym celem jego projektu dla C było utrzymanie języka blisko maszyny, a jednocześnie zapewnienie przenośności, czyli niezależności maszyny.

Aby uzyskać więcej informacji, zapoznaj się z oryginalnym artykułem BSTJ:

Dziękuję Dennis. Obyście spoczywali w pokoju.

bud wonsiewicz
źródło
3
To było w zasadzie napisane i ładniejsze opakowanie dla zestawu PDP, jeśli mnie pytasz.
einpoklum
2
@einpoklum Zwykle się z tym zgadzam. Nauczyłem się C w około 1980 roku na uniwersytecie, na PDP-11 / 34a, jak to się dzieje, i został opisany przez jednego z profesorów jako „przenośny język asemblera”. Prawdopodobnie dlatego, że oprócz PDP-11 mieliśmy w laboratorium kilka maszyn Superbrain CP / M, w których były dostępne kompilatory C. en.wikipedia.org/wiki/Intertec_Superbrain
dgnuff
2
Również doskonała odpowiedź oparta na weryfikowalnych dowodach historycznych (wow! Dostępna była wcześniejsza wersja K&R!).
Christophe
7
@einpoklum Czy to nie jest zbyt daleko idące? Miałem okazję pisać kod systemu i aplikacji w połowie lat 80-tych w asemblerze (Z80 i M68K), „przenośnym asemblerze” o nazwie M (składnia PDP11 z abstrakcyjnym rejestrem 16-bitowym i zestawem instrukcji) oraz C. W porównaniu z asemblerem , C jest zdecydowanie językiem wysokiego poziomu: wydajność programowania w C była o rząd wielkości wyższa niż w asemblerze! Oczywiście bez ciągów znaków (SNOBOL), bez natywnej obsługi plików danych (COBOL), bez samoczynnego generowania kodu (LISP), bez zaawansowanej matematyki (APL), bez obiektów (SIMULA), więc możemy zgodzić się, że nie był bardzo wysoki
Christophe
21

Jak napisałem gdzie indziej na tej stronie, gdy ktoś określił wzorzec zarządzania pamięcią malloc / wolną pamięcią jako „programowanie niskiego poziomu”,

Zabawne, jak zmienia się z czasem definicja „niskiego poziomu”. Kiedy uczyłem się programowania, każdy język, który zapewniał znormalizowany model sterty, który umożliwia prosty wzorzec alokacji / swobodnego, był rzeczywiście uważany za wysoki. W programowaniu niskiego poziomu musisz sam śledzić pamięć (nie alokacje, ale same lokalizacje pamięci!) Lub napisać własny alokator sterty, jeśli naprawdę masz ochotę.

Dla kontekstu miało to miejsce na początku lat 90., długo po wydaniu C.

Mason Wheeler
źródło
Czy standardowa biblioteka nie była tylko rzeczą od czasu standaryzacji pod koniec lat 80. (cóż, w oparciu o istniejące interfejsy API systemu Unix)? Ponadto programowanie jądra (które było pierwotną domeną problemów C) naturalnie wymaga rzeczy niskiego poziomu, takich jak ręczne zarządzanie pamięcią. W tym czasie C musiał być językiem programowania na najwyższym poziomie, w którym napisano poważne jądro (myślę, że obecnie jądro NT również używa sporej ilości C ++).
amon
6
@hyde, użyłem Algolu 60, dwóch różnych dialektów FORTRAN i kilku różnych dialektów BASIC już w latach siedemdziesiątych i żaden z tych języków nie miał wskaźników ani alokatora sterty.
Solomon Slow
7
Ściśle mówiąc, nadal możesz programować bez malloc(), bezpośrednio dzwoniąc brk(2)lub mmap(2)zarządzając wynikową pamięcią. Jest to masywny PITA bez możliwych korzyści (o ile nie zdarzy ci się być wdrożenie coś malloc-like), ale można to zrobić.
Kevin
1
@amon - z wyjątkiem niezwykłych maszyn opartych na stosie Burroughs, które zostały zaprogramowane w ALGOL od dołu do góry ... i znacznie wcześniej niż w Uniksie. Aha, a przy okazji, Multics, który był inspiracją dla Unix: Written in PL / I. Podobne do ALGOL, wyższy poziom niż C.
davidbak
6
W rzeczywistości powód, dla którego większość z nas nie korzysta z Multics, prawdopodobnie ma więcej wspólnego z faktem, że działał on tylko na piekielnie drogich komputerach mainframe - tj. Typowym oburzającym koszcie dnia głównego plus dodatkowy koszt pół szafki specjalistyczny sprzęt do implementacji pamięci wirtualnej z bezpieczeństwem. Kiedy pojawiły się 32-bitowe minikomputery, takie jak VAX-11, wszyscy oprócz banków i rządu wycofali się z IBM i siedmiu krasnoludków i przenieśli swoje przetwarzanie na dużą skalę na „mini” komputery.
davidbak
15

Wiele odpowiedzi odnosiło się już do wczesnych artykułów, w których stwierdzono, że „C nie jest językiem wysokiego poziomu”.

Nie mogę się jednak oprzeć stosowaniu: wiele, jeśli nie większość lub wszystkie HLL w tym czasie - Algol, Algol-60, PL / 1, Pascal - zapewniały sprawdzanie granic tablic i numeryczne wykrywanie przepełnienia.

Ostatnio sprawdziłem, czy przepełnienie bufora i liczb całkowitych było główną przyczyną wielu luk w zabezpieczeniach. ... Tak, wciąż sprawa ...

Sytuacja dynamicznego zarządzania pamięcią była bardziej skomplikowana, ale mimo to malloc / free w stylu C był wielkim krokiem wstecz pod względem bezpieczeństwa.

Więc jeśli twoja definicja HLL obejmuje „automatycznie zapobiega wielu błędom niskiego poziomu”, cóż, przepraszający stan cyberbezpieczeństwa byłby zupełnie inny, prawdopodobnie lepszy, gdyby C i UNIX nie miały miejsca.

Krazy Glew
źródło
7
Ponieważ zdarzyło mi się być zaangażowanym w implementację Intel MPX i kompilatora sprawdzającego wskaźnik / granice, który się wyłączył, mogę odesłać cię do dokumentów na temat ich wydajności: zasadniczo 5-15%. Wiele z nich obejmuje analizy kompilatorów, które były ledwo możliwe w latach 70. i 80. XX wieku - w porównaniu do naiwnych kontroli, które mogą być o 50% wolniejsze. Myślę jednak, że można śmiało powiedzieć, że C i UNIX cofnęły prace nad takimi analizami o 20 lat - kiedy C stał się najpopularniejszym językiem programowania, zapotrzebowanie na bezpieczeństwo było znacznie mniejsze.
Krazy Glew
9
@jamesqf Co więcej, wiele komputerów przed C posiadało specjalne wsparcie sprzętowe do sprawdzania granic i przelewania liczb całkowitych. Ponieważ C nie używał tego sprzętu, ostatecznie został wycofany i usunięty.
Krazy Glew
5
@jamesqf Na przykład: MIPS RISC ISA pierwotnie opierał się na testach porównawczych Stanforda, które pierwotnie zostały napisane w Pascalu, dopiero później przeniósł się do C. Ponieważ Pascal sprawdził, czy nie ma przepełnienia liczby całkowitej ze znakiem, dlatego też MIPS, w instrukcjach takich jak ADD. Około 2010 r. Pracowałem w MIPS, mój szef chciał usunąć nieużywane instrukcje w MIPSr6, a badania wykazały, że kontrole przepełnienia prawie nigdy nie były używane. Okazało się jednak, że Javascript przeprowadził takie kontrole - ale nie mógł skorzystać z tanich instrukcji z powodu braku obsługi systemu operacyjnego.
Krazy Glew
3
@KrazyGlew - To bardzo interesujące, że poruszasz tę kwestię, ponieważ w C / C ++ walka między użytkownikami i pisarzami kompilatora o „niezdefiniowane zachowanie” z powodu przepełnienia liczby całkowitej jest nagrzana, ponieważ dzisiejsi pisarze kompilatorów przyjęli starą mantrę „Robiąc źle program gorzej jest bez grzechu ”i podniósł go do 11. Mnóstwo postów na stackoverflow i gdzie indziej odzwierciedla to ...
davidbak
2
Jeśli Rust miałby wbudowane SIMD, takie jak C, mógłby to być prawie idealny nowoczesny przenośny język asemblera. C staje się coraz gorszy jako przenośny język asemblera z powodu agresywnej optymalizacji opartej na UB i braku możliwości przenośnego ujawnienia nowych prymitywnych operacji obsługiwanych przez nowoczesne procesory (takich jak popcnt, liczenie zer wiodących / końcowych, odwracanie bitów, odwracanie bajtów, nasycanie matematyka). Zmuszenie kompilatorów C do wydajnego asmowania tych procesorów z obsługą HW często wymaga nieprzenośnych elementów wewnętrznych. Posiadanie kompilatora emulującego popcnt na obiektach docelowych bez niego jest lepsze niż rozpoznawanie idiomów popcnt.
Peter Cordes,
8

Rozważ starsze i znacznie wyższe języki, które poprzedzały C (1972):

Fortran - 1957 (niewiele wyższy poziom niż C)

Lisp - 1958

Cobol - 1959

Fortran IV - 1961 (niewiele wyższy poziom niż C)

PL / 1 - 1964

APL - 1966

Plus język średniego poziomu, taki jak RPG (1959), głównie język programowania, który zastępuje systemy zapisu jednostek oparte na wtyczkach.

Z tej perspektywy C wydawał się językiem bardzo niskiego poziomu, tylko nieco powyżej makr asemblerów używanych wówczas na komputerach mainframe. W przypadku komputerów mainframe IBM makra asemblera były używane do dostępu do bazy danych, takie jak BDAM (podstawowa metoda dostępu do dysku), ponieważ interfejsy bazy danych nie zostały przeniesione do Cobola (w tym czasie), co skutkowało spuścizną połączenia zestawu i Programy Cobol są nadal używane na komputerach mainframe IBM.

rcgldr
źródło
2
Jeśli chcesz wymienić starsze, wyższe języki, nie zapomnij o LISP .
Deduplicator,
@Deduplicator - dodałem go do listy. Skupiłem się na tym, co było używane na komputerach mainframe IBM i nie przypominam sobie, aby LISP był tak popularny, ale APL był także niszowym językiem dla komputerów mainframe IBM (poprzez konsole współdzielenia czasu) i IBM 1130. Podobnie jak LISP, APL jest jednym z bardziej unikalne języki wysokiego poziomu, na przykład sprawdź, jak mało kodu potrzeba, aby stworzyć grę Conwaya w aktualnej wersji APL: youtube.com/watch?v=a9xAKttWgP4 .
rcgldr
2
Nie liczyłbym RPG lub COBOL jako szczególnie wysokiego poziomu, przynajmniej wcześniej niż COBOL-85. Kiedy zarysujesz powierzchnię COBOL, zobaczysz, że jest to w zasadzie zbiór bardzo zaawansowanych makr asemblera. Na początek brakuje zarówno funkcji, procedur i rekurencji, jak i wszelkiego rodzaju określania zakresu. Całe miejsce do przechowywania musi zostać zadeklarowane na początku programu, co prowadzi albo do bardzo długich uwertur, albo do bolesnego ponownego użycia zmiennych.
idrougge,
Mam złe wspomnienia z korzystania z Fortran IV, nie przypominam sobie, by był znacznie „wyższy poziom” niż C.
DaveG
@idrougge - COBOL i RPG, a także zestawy instrukcji dla komputerów mainframe zawierały pełną obsługę zapakowanego lub rozpakowanego BCD, wymaganego dla oprogramowania finansowego w krajach takich jak USA. Uważam, że powiązane rodzime operatory, takie jak „przenieś odpowiadający”, są na wysokim poziomie. RPG było niezwykłe, ponieważ określiłeś powiązanie między surowymi polami wejściowymi a sformatowanymi polami wyjściowymi i / lub akumulatorami, ale nie kolejność operacji, podobnie jak programowanie wtyczki, które zastąpiło.
rcgldr
6

Odpowiedź na twoje pytanie zależy od tego, o jaki język C pyta.

Język opisany w Dennis Ritchie's 1974 C Reference Manual był językiem niskiego poziomu, który oferował niektóre z wygody programowania w językach wyższego poziomu. Dialekty wywodzące się z tego języka również były niskopoziomowymi językami programowania.

Kiedy opublikowano normę C 1989/1990 C, nie opisywała ona języka niskiego poziomu, który stał się popularny przy programowaniu rzeczywistych maszyn, ale opisała język wyższego poziomu, który mógłby być - ale nie był wymagany - -implementowane na niższych poziomach.

Jak zauważają autorzy C Standard, jedną z rzeczy, które sprawiły, że język był użyteczny, było to, że wiele implementacji można było traktować jako asemblery wysokiego poziomu. Ponieważ C był również używany jako alternatywa dla innych języków wysokiego poziomu i ponieważ wiele aplikacji nie wymagało zdolności do robienia rzeczy, których języki wysokiego poziomu nie byłyby w stanie zrobić, autorzy Standardu zezwolili implementacjom na zachowanie się w dowolny sposób jeśli programy próbowały używać konstrukcji niskiego poziomu. W związku z tym język opisany w standardzie C nigdy nie był językiem programowania niskiego poziomu.

Aby zrozumieć to rozróżnienie, zastanów się, w jaki sposób Ritchie's Language i C89 mogłyby zobaczyć fragment kodu:

struct foo { int x,y; float z; } *p;
...
p[3].y+=1;

na platformie, gdzie „char” to 8 bitów, „int” to 16 bitów big-endian, „float” to 32 bity, a struktury nie mają specjalnych wymagań dotyczących dopełnienia lub wyrównania, więc rozmiar „struct foo” wynosi 8 bajtów.

W języku Ritchie zachowanie ostatniej instrukcji pobierałoby adres zapisany w „p”, dodawało do niego 3 * 8 + 2 [tj. 26] bajtów i pobierało 16-bitową wartość z bajtów pod tym adresem i następnym , dodaj jedną do tej wartości, a następnie zapisz tę 16-bitową wartość do tych samych dwóch bajtów. Zachowanie byłoby zdefiniowane jako działanie na 26. i 27. bajcie następującym po adresie pod adresem p, bez względu na rodzaj przechowywanego tam obiektu.

W języku zdefiniowanym w standardzie C, w przypadku, gdy * p identyfikuje element „struct foo []”, po którym następują co najmniej trzy bardziej kompletne elementy tego typu, ostatnia instrukcja doda jeden element do elementu y trzeci element po * p. Zachowanie nie byłoby zdefiniowane przez Standard w żadnych innych okolicznościach.

Język Ritchie był językiem programowania niskiego poziomu, ponieważ chociaż pozwalał programiście korzystać z abstrakcji, takich jak tablice i struktury, gdy było to wygodne, definiował zachowanie pod względem podstawowego układu obiektów w pamięci. Natomiast język opisany w C89 i późniejszych standardach definiuje rzeczy w kategoriach abstrakcji wyższego poziomu i definiuje tylko zachowanie kodu, które jest z tym zgodne. Wdrożenia wysokiej jakości odpowiednie dla programowania niskiego poziomu będą zachowywały się użytecznie w większej liczbie przypadków niż wymaga tego norma, ale nie ma „oficjalnego” dokumentu określającego, co wdrożenie musi zrobić, aby było odpowiednie do takich celów.

Język C wymyślony przez Dennisa Ritchiego jest zatem językiem niskiego poziomu i został uznany za taki. Język wymyślony przez Komitet ds. Norm C nigdy jednak nie był językiem niskiego poziomu przy braku gwarancji zapewniających wdrożenie, które wykraczają poza mandaty Standardu.

supercat
źródło