Czy C jest silnie wpisane?


88

Cytując Wikipedię :

Dwa powszechnie używane języki, które obsługują wiele rodzajów niejawnej konwersji to C i C ++ i czasami twierdzi się, że są to języki słabo typowane. Jednak inni twierdzą, że języki te nakładają wystarczające ograniczenia na sposób mieszania operandów różnych typów, że oba te języki należy traktować jako języki silnie typowane.

Czy jest bardziej ostateczna odpowiedź?


188
Dla programisty C mocne pisanie oznacza mocniejsze naciskanie klawiszy.
Dan Dyer,

2
C jest po słabej stronie kontinuum pisania. Ale po obu stronach jest wystarczająco dużo elementów, że możesz się spierać. Skoro już to robisz, równie dobrze możesz zapytać (vi lub emacs, netbeans lub eclipse, itp.)
Cervo

4
Stan Wikipedii był na tyle zły, że czułem się zmuszony do edycji kilku stron Wikipedii. Może teraz jest trochę lepiej. Może.
Norman Ramsey,

40
Odp .: Komentarz Dana (aby podać uznanie tam, gdzie jest to należne) Książka Petera van der Lindena „Expert C Programming” zawiera następujący wiersz: „Do dziś wielu programistów C uważa, że„ mocne pisanie oznacza po prostu mocniejsze uderzanie w klawiaturę ”.
Alexandros Gezerlis

Bardzo dobre pytanie !!!
Destructor,

Odpowiedzi:


154

„Silnie wpisane” i „słabo wpisane” to terminy, które nie mają szeroko uzgodnionego technicznego znaczenia. Terminy, które mają dobrze zdefiniowane znaczenie

  • Typ dynamiczny oznacza, że ​​typy są dołączane do wartości w czasie wykonywania, a próba zmieszania wartości różnych typów może spowodować „błąd typu w czasie wykonywania”. Na przykład, jeśli w Scheme spróbujesz dodać jeden do true, pisząc (+ 1 #t), spowoduje to błąd. Błąd występuje tylko wtedy, gdy próbujesz wykonać niewłaściwy kod.

  • Typ statyczny oznacza, że ​​typy są sprawdzane w czasie kompilacji, a program, który nie ma typu statycznego, jest odrzucany przez kompilator. Na przykład, jeśli w ML spróbujesz dodać jeden do true przez zapis 1 + true, program zostanie odrzucony z (prawdopodobnie tajemniczym) komunikatem o błędzie. Zawsze pojawia się błąd, nawet jeśli kod może nigdy nie zostać wykonany.

Różni ludzie preferują różne systemy po części ze względu na to, jak bardzo cenią sobie elastyczność i jak bardzo martwią się błędami w czasie wykonywania.

Czasami określenie „silnie wpisane” jest używane luźno na oznaczenie „wpisane statycznie”, a „słabo wpisane” jest używane niepoprawnie, aby oznaczać „wpisane dynamicznie”. Lepszym zastosowaniem terminu „silnie typowany” jest to, że „nie można obejść lub obalić systemu typów”, podczas gdy „słabo wpisany” oznacza „istnieją luki w systemie typów”. Przewrotnie, większość języków ze statycznymi systemami typów ma luki, podczas gdy wiele języków z dynamicznymi systemami typów nie ma luk.

Żaden z tych terminów nie jest w żaden sposób powiązany z liczbą niejawnych konwersji dostępnych w języku.

Jeśli chcesz mówić dokładnie o językach programowania, najlepiej unikać terminów „silnie wpisane” i „słabo wpisane”. Powiedziałbym, że C to język, który jest zapisywany statycznie, ale ma wiele luk. Jedną z luk jest to, że możesz dowolnie rzutować dowolny typ wskaźnika na dowolny inny typ wskaźnika. Możesz także utworzyć lukę między dowolnymi dwoma wybranymi typami, deklarując związek C, który ma dwóch członków, po jednym dla każdego z typów, o których mowa.

Więcej o statycznym i dynamicznym typowaniu pisałem w artykule Why-interpreted-langs-are-Most-ducktyped-while-compiled-have-strong-typing .


2
Skąd wziąłeś definicje, które sugerowałeś dla mocnego / słabego pisania (ta luka)?
Sydius,

2
Po co Ci „luka” w dynamicznym środowisku pisania?
Chris Conway,

4
@Sydius: Od spędzenia większości ostatnich 20 lat na spotkaniach z ludźmi, którzy projektują, budują i analizują języki programowania i systemy typograficzne. To moja płatna praca :-)
Norman Ramsey

@Chris: Nigdy nie widziałem języka dynamicznie wpisywanego z „luką”. Typowym zastosowaniem luki jest praca z systemem wykonawczym lub systemem operacyjnym, np. Pobranie surowego adresu i przekonwertowanie go na wskaźnik do dobrze zachowanej wartości językowej. Mógłbyś to zrobić w dynamicznym otoczeniu, ale nie znam żadnych prób.
Norman Ramsey

1
@NormanRamsey Myślę, że Chris odnosił się w swoim pytaniu do:whereas "weakly typed" means "there are loopholes in the type system
Nir Alfasi

23

Trudno jest sklasyfikować każdy język jako „słabo” lub „silnie” typowany - to raczej kontinuum. Ale w porównaniu z innymi językami C jest dość silnie wpisane na maszynie. Każdy obiekt ma typ czasu kompilacji, a kompilator poinformuje Cię (głośno), jeśli robisz coś z obiektem, na co nie pozwala jego typ. Na przykład nie można wywoływać funkcji z niewłaściwymi typami parametrów, uzyskać dostępu do nieistniejących członków struktury / unii itp.

Ale jest kilka słabości. Jedną z głównych słabości są typy typów - zasadniczo mówią, że będziesz grzebać w typach obiektów, a kompilator powinien być cichy (jeśli może). void*to także kolejna słabość - jest to ogólny wskaźnik do nieznanego typu, a kiedy ich używasz, musisz być szczególnie ostrożny, aby postępować właściwie. Kompilator nie może statycznie sprawdzić większości zastosowań void*. void*można również przekonwertować na wskaźnik do dowolnego typu bez rzutowania (tylko w C, nie w C ++), co jest kolejną słabością.


Dobra odpowiedź, chociaż przeszkadza mi „typowanie ... i kompilator powinien być cichy”. Rzutowanie typu nie jest jak wyłączenie ostrzeżenia, w rzeczywistości zmienia interpretację wartości, do której się odwołuje.
Tall Jeff

15
Mylisz „statyczny” i „silny” w odniesieniu do pisania. Te dwie koncepcje są od siebie niezależne.
bendin

1
Dennis Richie (autor w C) nazwał C „silnie wpisanym i słabo sprawdzonym”
TimZaman

11

Literatura nie jest tego jasna. Myślę, że silnie wpisane nie jest tak / nie, istnieją różne stopnie silnego pisania.

Język programowania ma specyfikację sposobu wykonywania programów. Czasami nie jest jasne, jak wykonać określone programy. Na przykład programy, które próbują odjąć ciąg znaków od liczby. Lub programy, które dzielą przez zero. Istnieje kilka sposobów radzenia sobie z tymi warunkami. Niektóre języki mają reguły postępowania z takimi błędami (na przykład zgłaszają wyjątek). Inne języki po prostu nie mają reguł radzenia sobie w takich sytuacjach. Te języki na ogół mają systemy typów, które zapobiegają kompilowaniu programów, które prowadzą do nieokreślonego zachowania. Istnieją również języki, które mają nieokreślone zachowanie i nie mają systemu typów zapobiegającego tym błędom w czasie kompilacji (jeśli napiszesz program, który osiąga nieokreślone zachowanie, może on wystrzelić pociski).

Więc:

Języki, które określają, co dzieje się w czasie wykonywania w każdym przypadku (na przykład dodawanie liczby do ciągu), nazywane są dynamicznie typowanymi. Języki, które uniemożliwiają wykonywanie programów z błędami w czasie kompilacji, są wpisywane statycznie. Języki, które nie określają, co się dzieje, a także nie mają systemu typów zapobiegającego błędom, nazywane są słabo wpisanymi.

Czy więc Java jest wpisywana statycznie? Tak, ponieważ jego system typów nie pozwala na odejmowanie ciągu znaków od liczby. Nie, ponieważ umożliwia dzielenie przez zero. Możesz zapobiec dzieleniu przez zero w czasie kompilacji w systemie typów. Na przykład tworząc typ liczbowy, który nie może być zerem (np. NonZeroInt) i pozwala na dzielenie tylko przez liczby, które mają ten typ.

Czy więc C jest wpisane silnie czy słabo? C jest silnie wpisane, ponieważ system typów nie zezwala na niektóre błędy typu. Ale jest słabo wpisany w innych przypadkach, gdy nie jest zdefiniowane, co się dzieje (a system typów cię nie chroni).


Podoba mi się twoje wyrównywanie dynamiki i statyczności jako formy silnej i słabej. Jednak nie jestem pewien, czy rozumiem twój punkt widzenia, że ​​systemy statycznie typowane przestają dzielić przez zero. Jeśli mój typ statyczny intpobiera wartość z argumentów użytkownika lub wiersza poleceń lub z pliku, kompilator nie może nic zrobić, aby przestać być zerem!
Rikki

1
Istnieją statyczne systemy typów, które temu zapobiegają, ale większość języków jest albo słabo, albo dynamicznie „wpisywana” w odniesieniu do dzielenia przez zero, ponieważ jest to niezdefiniowane zachowanie (C) lub generują wyjątek (Java).
Jules

11

C jest uważane za słabo wpisane, ponieważ można przekonwertować dowolny typ na dowolny inny typ poprzez rzutowanie, bez błędu kompilatora. Więcej na ten temat przeczytasz tutaj .


2
wikipedia wprowadza tutaj w błąd. C jest silnie wpisane, typy są bardzo poprawne i kompilator będzie działał, jeśli je pomylisz, jednak C zapewnia również funkcje pozwalające ominąć to. Porównaj z językami takimi jak BCPL, które mają tylko typ „bajtowy”.
gbjbaanb

12
Słabo typizowany nie oznacza, że ​​język nie ma żadnych typów, oznacza po prostu, że typy mogą być niejawnie wymuszane z jednego typu na inny. Porównaj z Pythonem, silnie typizowanym językiem, w którym musisz jawnie konwertować typy za pomocą wywołań funkcji.
mipadi

Czy możliwość rzucenia czegoś w C również przyczynia się do tego, że jest to typ słaby. ?? Mam tę wątpliwość na zawsze
Suraj Jain

8

C jest silniej wpisane niż JavaScript i mniej silnie wpisane niż Ada.

Powiedziałbym, że bardziej pasuje do silnie wpisanej strony kontinuum. ale ktoś inny może się nie zgodzić (nawet jeśli się myli).

Jak to jest ostateczne?


To była nieco żartobliwa odpowiedź. Ale opowiedz o błędzie.
Michael Burr,

1
JavaScript jest silnie wpisany. Po prostu nie jest wpisywany statycznie. Wszystkie kontrole typów mają miejsce w czasie wykonywania (dynamiczne, a nie statyczne), ale zdarzają się i zapobiegają uszkodzeniu pamięci (jeden z aspektów silnego pisania).
bendin

5
Cóż, jak wskazuje bardzo dobra odpowiedź Norma Ramseya, „silnie wpisane” i „słabo wpisane” nie są szczególnie dobrze zdefiniowanymi terminami. Ponadto, o ile Javascript jest silnie wpisywany na maszynie, niektórzy mogą sądzić, że („4” / „2”) będące prawidłowym wyrażeniem JavaScript może oznaczać inaczej.
Michael Burr

5

C jest uważane za statycznie typowane (nie możesz zmienić zmiennej z int na float). Po zadeklarowaniu zmiennej utknie w ten sposób.

Ale jest uważany za słabo wpisany, ponieważ typy można przerzucić na flopie.

Co to jest 0? '\ 0', FALSE, 0.0 itd.

w wielu językach nie można powiedzieć JEŻELI (zmienna), ponieważ warunki będą przyjmować tylko wartości logiczne z wyrażeń boolowskich. Te są silniej wpisane. To samo dotyczy przechodzenia między znakami i liczbami całkowitymi.

zasadniczo c ma dwa główne proste typy danych, liczby całkowite i liczby zmiennoprzecinkowe (choć z różnymi dokładnościami). Wszystkie inne wartości logiczne, wyliczenia (nie proste, ale pasujące) itp. Są zaimplementowane jako jedne z nich. Nawet znaki są w zasadzie liczbami całkowitymi.

Porównaj z innymi językami, w których istnieją typy ciągów, typy wyliczeniowe, które można przypisać tylko do zdefiniowanych wartości, typy logiczne, w których można używać tylko wyrażeń generujących wartości logiczne lub prawda / fałsz.

Ale można argumentować, że w porównaniu do Perl C jest silnie wpisany. Jest to więc jeden z tych słynnych argumentów (vi vs emacs, linux vs windows, itp.). C # jest silniejszym typem niż C. Zasadniczo można dyskutować w obie strony. Twoje odpowiedzi prawdopodobnie pójdą w obie strony :) Również w niektórych podręcznikach / stronach internetowych będzie napisane, że C jest napisane słabo, a inne powiedzą, że C jest napisane silnie. Jeśli przejdziesz do wikipedii, wpis w C mówi „częściowo słabe pisanie”. Powiedziałbym, że w porównaniu do Pythona C jest napisany słabo. Więc Python / C #, C, Perl na kontinuum.


Proszę wyjaśnić swoje rozumowanie, że Perl jest wpisywany mniej silnie niż C.
user51568

print "Testowanie" + 0 # perl zrobi 0; $ var = "string"; $ var = 1; $ var = 123,4; Co to za zmienna?
Cervo

W C char * test = "testing"; printf (testowanie + 0); nadal będzie ciągiem, po prostu w C indeks ulegnie zmianie, jeśli zamiast zera użyję liczby. Wciąż jest dość słaby, ale nieco silniejszy niż Perl. test char *; test = 0; test = 123,4; test = "c"; ... mój kompilator generuje błędy
Cervo

błąd mówi, że rzut jest wymagany. Mimo to jest nieco silniejszy do sprawdzania typu niż Perl, więc w ramach kontinuum muszę powiedzieć, że C jest silniej wpisane niż Perl. Nadal możesz przejść test = (char *), a następnie użyć 0, 123.4, 'C', itd. Ale po prostu to jest błąd.
Cervo

4

Wiele dobrych odpowiedzi. Chcę poruszyć ważny punkt z Real World Haskell :

Warto mieć świadomość, że wiele społeczności językowych ma własne definicje „silnego typu”. Niemniej jednak omówimy krótko i ogólnie pojęcie siły w systemach czcionek.

(fantastyczna okazja)

Fajerwerki wokół systemów czcionek mają swoje korzenie w zwykłym angielskim, gdzie ludzie przypisują wartościowe słowa „słaby” i „silny”: zazwyczaj myślimy o sile jako lepszej niż słabości. O wiele więcej programistów mówi prostym językiem niż żargonem akademickim, i dość często akademicy naprawdę rzucają cegiełkami w każdy system typów, który nie odpowiada ich wyobraźni. Rezultatem jest często ta popularna rozrywka internetowa, wojna o płomienie.

Spójrz więc na odpowiedzi dotyczące C i C ++, ale pamiętaj, że „mocne” i „słabe” nie są odwzorowywane na „dobre” i „złe”.


4

Według Dennisa Ritchiego ( twórcy C ) i Briana Kernighana, C nie jest językiem silnie typowanym. Poniższe wiersze pochodzą z książki Język programowania C, strona 3, paragraf 5

C nie jest językiem silnie typizowanym, ale w miarę ewolucji jego sprawdzanie typów zostało wzmocnione.


3

Moim zdaniem C / C ++ są silnie wpisane. Typy hacków, które pozwalają na konwersję typów (void *), są spowodowane bliskością C do maszyny. Innymi słowy, możesz wywoływać polecenia asemblera z Pascala i manipulować wskaźnikami, a Pascal jest nadal uważany za język silnie typizowany. Możesz wywoływać pliki wykonywalne assemblera i C z Java poprzez JNI, ale nie powoduje to słabego typowania Java.

C ma po prostu „osadzony” asembler z surowymi wskaźnikami i tym podobne.


3

Termin silnie wpisany na maszynie nie ma uzgodnionej definicji. Dlatego jeśli nie zdefiniujesz, co masz na myśli przez „mocno wpisane”, nie możesz odpowiedzieć na twoje pytanie.

Z mojego doświadczenia wynika , że terminy „silnie wpisane” i „słabo wpisane” są używane wyłącznie przez trolle, ponieważ ich brak definicji pozwala trollom na przedefiniowanie ich w trakcie dyskusji, aby dopasować się do ich programu. Poza rozpoczęciem ostrzału, terminy te są prawie bezużyteczne.

Możesz również rzucić okiem na jakie są kluczowe aspekty silnie wpisywanego języka? tutaj w StackOverflow.


3
Nie zgadzam się. „Silnie wpisana” oznacza, że ​​możliwe jest określenie typu danych wartości i dozwolone są tylko operacje odpowiednie dla tego typu. Adresy „dynamiczne” i „statyczne”, kiedy można to określić.
joel.neely

2
Ci zrobić sobie sprawę z ironii próbuje obalić twierdzenie, że nie ma uzgodnionej definicji, wprowadzając kolejną definicję, prawda?
Jörg W Mittag

1
@Jorg: Nie próbuję przedstawiać kolejnego; podając tylko ten, który jest powszechnie używany w kręgach, w których się poruszam.
joel.neely

1

Istnieje ciągłość z wieloma równoległymi ścieżkami między „słabo wpisanymi” i „silnie wpisanymi”, dwoma terminami, które nie są nawet dobrze zdefiniowane.

C jest wpisywane statycznie, co oznacza , że kompilator wie, jaki jest zadeklarowany typ każdej zmiennej lokalnej i elementu członkowskiego struktury.

Języki z typami dynamicznymi mogą nadal być silnie wpisane, jeśli każdy obiekt ma określony typ, ale kompilator nie ma możliwości poznania tego typu.


0

Jaki jest powód Twojego zapytania? Powodem, dla którego pytam, jest niewielka różnica, a twoje szczególne użycie „silnie wpisanego” może wymagać mniej lub więcej wyjaśnienia. Zdecydowanie powiedziałbym, że Java i inne języki mają ściślejsze ograniczenia dotyczące niejawnej konwersacji typu.


Głównie z ciekawości, ale ubiegam się o stanowisko C i chciałem wiedzieć na wypadek, gdyby mnie o to zapytali.
Sydius,

Wtedy prawdopodobnie dłuższa odpowiedź, która podaje niuanse tego, co jest „silnie wpisane”, jest najlepszym podejściem, zamiast zwykłego powiedzenia „tak” lub „nie”.
BobbyShaftoe

0

Trudno jest udzielić konkretnej odpowiedzi, gdy nie ma konkretnej definicji „silnie wpisanej na maszynie”. Powiedziałbym, że C jest silnie wpisane, że każda zmienna i każde wyrażenie ma typ, ale słabo wpisane, co pozwala na zmianę typów za pomocą rzutowania i reinterpretację reprezentacji jednego typu jako drugiego.


Jest oficjalna pok. dla silnie wpisanych. Mówi, że plik sys. jest ST, gdy gwarantuje się, że nie ma błędu typu czasu wykonywania. Przykład: ML, Haskell. Jest to przydatne, aby system pomijał znaczniki typu wewnątrz obiektów, a jednak stosował operatory do poprawnych typów. Ponieważ wiemy przed wykonaniem, że nie ma potrzeby stosowania tagów w obiektach. Ponieważ C ma rzutowanie i dostęp do wskaźnika do dowolnej notatki, C nie jest st
alinsoar

0

Powiedziałbym, że C jest tak silnie wpisane, jak dyktuje twój kompilator / platforma. Na przykład, jeśli budujesz na ścisłej platformie, wyłuskiwanie wskaźnika typu przebijanego prawdopodobnie się zepsuje:

void m_free(void **p)
{
        if (*p != NULL) {
                free(*p);
                *p = NULL;
        }
}

....
char *str = strdup("foo");
m_free((void **) &foo);

Teraz, jeśli powiesz kompilatorowi, aby pominął ścisłe aliasowanie, nie byłoby to problemem, ale niezbyt przenośnym. W tym sensie przesuwanie granic języka jest możliwe, ale prawdopodobnie nie jest najlepszym pomysłem. To wykracza poza typowe casting, tj. Casting int tak długo i naprawdę pokazuje jedną z możliwych pułapek void.

Więc powiedziałbym, że C jest w zasadzie ściśle typowane, ale jego różne kompilatory zakładają, że programista wie najlepiej i pozwala na pewną elastyczność. To naprawdę zależy od kompilatora, niektórzy nie wychwycą tego potencjalnych błędów. W tym sensie wybrany kompilator naprawdę odgrywa rolę przy udzielaniu odpowiedzi na pytanie. To, co jest poprawne, często różni się od tego, na co pozwala kompilator.



-1

Niezbyt mocno wpisane.

Zastanów się, co poniższy prototyp funkcji mówi o typach danych argumentów:

void func (int n, char ch, ...);

Nic. Sugeruję więc, że mocne pisanie tutaj nie ma zastosowania.


Co? Mówi, że istnieje int, po którym następuje znak, po którym następuje dowolna liczba argumentów dowolnego typu. To nie jest „nic”.
Lawrence Dol

... nie mówi nic o typach przekazywanych argumentów. Prawdą jest, że znany jest typ samej funkcji . Tak powiedział Software Monkey.
Johannes Schaub - litb

Właśnie o tych „dowolnych argumentach dowolnego typu” mówię. Łańcuch jest tak mocny, jak jego najsłabsze ogniwo.
joel.neely

-3

Powiedziałbym, że jest to typ silnie typowy, ponieważ każde wyrażenie ma typ, który nie jest funkcją jego wartości; ei można to poznać przed uruchomieniem.

OTOH Nie jestem pewien, czy jest to poprawny opis silnie wpisanego. Jedynym silniejszym twierdzeniem, jakie widzę dla języka, jest zapewnienie, że nie można obalić systemu typów w czasie wykonywania poprzez reinterpretację rzutowania typów, związków, wywołań do innych języków, wskaźników, języka asemblera itp. Języki takie jak ten istnieją, ale są tak okaleczeni, że wydają się nie interesować programistów spoza środowiska akademickiego i akademickiego. Jak ktoś zauważył, aby naprawdę zrobić to dobrze, musisz mieć takie typy nonZeroInti inne. Fuj.


3
Co nie jest? Moja definicja silnego typu lub C?
BCS
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.